summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKristofer Pettersson <kristofer.pettersson@sun.com>2009-10-19 09:43:33 +0200
committerKristofer Pettersson <kristofer.pettersson@sun.com>2009-10-19 09:43:33 +0200
commit834ba32293173639880423839bbd245c601c0d50 (patch)
tree89e9504b75534f7f836f5aed34370d36c39f277d
parentc2c12c240269eafc21c6d3fc6a9f0a41c4eaed20 (diff)
downloadmariadb-git-834ba32293173639880423839bbd245c601c0d50.tar.gz
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.
-rw-r--r--mysql-test/r/sp.result45
-rw-r--r--mysql-test/t/sp.test46
-rw-r--r--sql/sql_yacc.yy61
3 files changed, 137 insertions, 15 deletions
diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result
index 67514c314f4..752edf8db41 100644
--- a/mysql-test/r/sp.result
+++ b/mysql-test/r/sp.result
@@ -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
# ------------------------------------------------------------------
diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test
index 44c4556340e..328dde4b26f 100644
--- a/mysql-test/t/sp.test
+++ b/mysql-test/t/sp.test
@@ -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 # ------------------------------------------------------------------
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 12e124230e5..ceebde4f7b3 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -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
{