Commit 834ba322 authored by Kristofer Pettersson's avatar Kristofer Pettersson

Bug#47627 SET @@{global.session}.local_variable in stored routine causes crash

Adding @@session and @@global prefixes to a
declared variable in a stored procedure the server
would lead to a crash.

The reason was that during the parsing of the
syntactic rule 'option_value' an uninitialized
set_var object was pushed to the parameter stack
of the SET statement. The parent rule
'option_type_value'  interpreted the existence of
variables on the parameter stack as an assignment
and wrapped it in a sp_instr_set object.

As the procedure later was executed an attempt
was made to run the method 'check()' on an
uninitialized member object (NULL value) belonging
to the previously created but uninitialized object.


sql/sql_yacc.yy:
  * Assign the option_type at once since it is needed by the next
    parsing rule (internal_variable_name)
  * Rearranged the if statement to reduce negations and gain more
    clarity of code.
  * Added check for option_type to better detect if current
    variable is a SP local variable or a system variable.
parent c2c12c24
......@@ -6979,6 +6979,51 @@ CALL p1;
ERROR 42S22: Unknown column 'A.b' in 'IN/ALL/ANY subquery'
DROP PROCEDURE p1;
DROP TABLE t1, t2;
#
# Bug47627 SET @@{global.session}.local_variable in stored routine causes crash
#
DROP PROCEDURE IF EXISTS p1;
DROP PROCEDURE IF EXISTS p2;
DROP PROCEDURE IF EXISTS p3;
CREATE PROCEDURE p1()
BEGIN
DECLARE v INT DEFAULT 0;
SET @@session.v= 10;
END//
ERROR HY000: Unknown system variable 'v'
CREATE PROCEDURE p2()
BEGIN
DECLARE v INT DEFAULT 0;
SET v= 10;
END//
call p2()//
CREATE PROCEDURE p3()
BEGIN
DECLARE v INT DEFAULT 0;
SELECT @@session.v;
END//
ERROR HY000: Unknown system variable 'v'
CREATE PROCEDURE p4()
BEGIN
DECLARE v INT DEFAULT 0;
SET @@global.v= 10;
END//
ERROR HY000: Unknown system variable 'v'
CREATE PROCEDURE p5()
BEGIN
DECLARE v INT DEFAULT 0;
SET @@global.query_cache_size= 0;
SET @@session.identity= 1;
SELECT @@session.identity;
SELECT @@global.query_cache_size;
END//
CALL p5();
@@session.identity
1
@@global.query_cache_size
0
DROP PROCEDURE p2;
DROP PROCEDURE p5;
# ------------------------------------------------------------------
# -- End of 5.1 tests
# ------------------------------------------------------------------
......@@ -8263,7 +8263,51 @@ CALL p1;
DROP PROCEDURE p1;
DROP TABLE t1, t2;
--echo #
--echo # Bug47627 SET @@{global.session}.local_variable in stored routine causes crash
--echo #
--disable_warnings
DROP PROCEDURE IF EXISTS p1;
DROP PROCEDURE IF EXISTS p2;
DROP PROCEDURE IF EXISTS p3;
--enable_warnings
delimiter //;
--error ER_UNKNOWN_SYSTEM_VARIABLE
CREATE PROCEDURE p1()
BEGIN
DECLARE v INT DEFAULT 0;
SET @@session.v= 10;
END//
CREATE PROCEDURE p2()
BEGIN
DECLARE v INT DEFAULT 0;
SET v= 10;
END//
call p2()//
--error ER_UNKNOWN_SYSTEM_VARIABLE
CREATE PROCEDURE p3()
BEGIN
DECLARE v INT DEFAULT 0;
SELECT @@session.v;
END//
--error ER_UNKNOWN_SYSTEM_VARIABLE
CREATE PROCEDURE p4()
BEGIN
DECLARE v INT DEFAULT 0;
SET @@global.v= 10;
END//
CREATE PROCEDURE p5()
BEGIN
DECLARE v INT DEFAULT 0;
SET @@global.query_cache_size= 0;
SET @@session.identity= 1;
SELECT @@session.identity;
SELECT @@global.query_cache_size;
END//
delimiter ;//
CALL p5();
DROP PROCEDURE p2;
DROP PROCEDURE p5;
--echo # ------------------------------------------------------------------
--echo # -- End of 5.1 tests
--echo # ------------------------------------------------------------------
......@@ -11783,8 +11783,17 @@ option_type:
;
option_type2:
/* empty */ { $$= OPT_DEFAULT; }
| ONE_SHOT_SYM { Lex->one_shot_set= 1; $$= OPT_SESSION; }
/* empty */
{
$$= OPT_DEFAULT;
Lex->option_type= OPT_DEFAULT;
}
| ONE_SHOT_SYM
{
Lex->one_shot_set= 1;
$$= OPT_SESSION;
Lex->option_type= OPT_SESSION;
}
;
opt_var_type:
......@@ -11795,10 +11804,26 @@ opt_var_type:
;
opt_var_ident_type:
/* empty */ { $$=OPT_DEFAULT; }
| GLOBAL_SYM '.' { $$=OPT_GLOBAL; }
| LOCAL_SYM '.' { $$=OPT_SESSION; }
| SESSION_SYM '.' { $$=OPT_SESSION; }
/* empty */
{
$$=OPT_DEFAULT;
Lex->option_type= OPT_DEFAULT;
}
| GLOBAL_SYM '.'
{
$$=OPT_GLOBAL;
Lex->option_type= OPT_GLOBAL;
}
| LOCAL_SYM '.'
{
$$=OPT_SESSION;
Lex->option_type= OPT_SESSION;
}
| SESSION_SYM '.'
{
$$=OPT_SESSION;
Lex->option_type= OPT_SESSION;
}
;
ext_option_value:
......@@ -12038,8 +12063,22 @@ internal_variable_name:
sp_pcontext *spc= lex->spcont;
sp_variable_t *spv;
/* We have to lookup here since local vars can shadow sysvars */
if (!spc || !(spv = spc->find_variable(&$1)))
/*
We have to lookup here since local vars can shadow sysvars.
We also have to inspect the option_type first since the variable
identifier might have been prefixed with @@session or @@global
prefixes. Without this check we would wrongly identify them
as SP local variables.
*/
if (lex->option_type == OPT_DEFAULT && spc &&
(spv= spc->find_variable(&$1)))
{
/* An SP local variable */
$$.var= NULL;
$$.base_name= $1;
}
else
{
/* Not an SP local variable */
sys_var *tmp=find_sys_var(thd, $1.str, $1.length);
......@@ -12056,12 +12095,6 @@ internal_variable_name:
lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT;
}
}
else
{
/* An SP local variable */
$$.var= NULL;
$$.base_name= $1;
}
}
| ident '.' ident
{
......
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