From 054d00a9a3918fd4551bd5583256a3183802cdae Mon Sep 17 00:00:00 2001 From: Alexander Barkov Date: Mon, 3 Oct 2016 10:33:22 +0400 Subject: [PATCH] A fix for MDEV-10411 Providing compatibility for basic PL/SQL constructs (Part 6: Assignment operator) Fixed that a crash in this script: SET sql_mode=ORACLE; max_sort_length:= 1024; --- .../suite/compat/oracle/r/variables.result | 39 +++++++++++++++ .../suite/compat/oracle/t/variables.test | 38 +++++++++++++++ sql/sql_lex.cc | 29 ++++++++++++ sql/sql_lex.h | 1 + sql/sql_yacc.yy | 25 +--------- sql/sql_yacc_ora.yy | 47 ++----------------- 6 files changed, 114 insertions(+), 65 deletions(-) create mode 100644 mysql-test/suite/compat/oracle/r/variables.result create mode 100644 mysql-test/suite/compat/oracle/t/variables.test diff --git a/mysql-test/suite/compat/oracle/r/variables.result b/mysql-test/suite/compat/oracle/r/variables.result new file mode 100644 index 00000000000..a7067d7b3fd --- /dev/null +++ b/mysql-test/suite/compat/oracle/r/variables.result @@ -0,0 +1,39 @@ +SET sql_mode=oracle; +# +# MDEV-10411 Providing compatibility for basic PL/SQL constructs +# Part 6: Assignment operator +# +max_sort_length:=1030; +SELECT @@max_sort_length; +@@max_sort_length +1030 +max_sort_length:=DEFAULT; +# +# Testing that SP variables shadow global variables in assignments +# +CREATE PROCEDURE p1 +AS +BEGIN +max_sort_length:=1030; +DECLARE +max_sort_length INT DEFAULT 1031; +BEGIN +SELECT @@max_sort_length, max_sort_length; +max_sort_length:=1032; +SELECT @@max_sort_length, max_sort_length; +END; +SELECT @@max_sort_length; +max_sort_length:= DEFAULT; +END; +$$ +CALL p1(); +@@max_sort_length max_sort_length +1030 1031 +@@max_sort_length max_sort_length +1030 1032 +@@max_sort_length +1030 +DROP PROCEDURE p1; +# +# End of MDEV-10411 Providing compatibility for basic PL/SQL constructs (part 6) +# diff --git a/mysql-test/suite/compat/oracle/t/variables.test b/mysql-test/suite/compat/oracle/t/variables.test new file mode 100644 index 00000000000..4705cac11c0 --- /dev/null +++ b/mysql-test/suite/compat/oracle/t/variables.test @@ -0,0 +1,38 @@ +SET sql_mode=oracle; + +--echo # +--echo # MDEV-10411 Providing compatibility for basic PL/SQL constructs +--echo # Part 6: Assignment operator +--echo # + +max_sort_length:=1030; +SELECT @@max_sort_length; +max_sort_length:=DEFAULT; + +--echo # +--echo # Testing that SP variables shadow global variables in assignments +--echo # + +DELIMITER $$; +CREATE PROCEDURE p1 +AS +BEGIN + max_sort_length:=1030; + DECLARE + max_sort_length INT DEFAULT 1031; + BEGIN + SELECT @@max_sort_length, max_sort_length; + max_sort_length:=1032; + SELECT @@max_sort_length, max_sort_length; + END; + SELECT @@max_sort_length; + max_sort_length:= DEFAULT; +END; +$$ +DELIMITER ;$$ +CALL p1(); +DROP PROCEDURE p1; + +--echo # +--echo # End of MDEV-10411 Providing compatibility for basic PL/SQL constructs (part 6) +--echo # diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index bf19ac34b67..585f9b19370 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -5922,6 +5922,35 @@ bool LEX::add_resignal_statement(THD *thd, const sp_condition_value *v) } +/* + Perform assignment for a trigger, a system variable, or an SP variable. + "variable" be previously set by init_internal_variable(variable, name). +*/ +bool LEX::set_variable(struct sys_var_with_base *variable, Item *item) +{ + if (variable->var == trg_new_row_fake_var) + { + /* We are in trigger and assigning value to field of new row */ + return set_trigger_new_row(&variable->base_name, item); + } + if (variable->var) + { + /* It is a system variable. */ + return set_system_variable(variable, option_type, item); + } + + /* + spcont and spv should not be NULL, as the variable + was previously checked by init_internal_variable(). + */ + DBUG_ASSERT(spcont); + sp_variable *spv= spcont->find_variable(variable->base_name, false); + DBUG_ASSERT(spv); + /* It is a local variable. */ + return set_local_variable(spv, item); +} + + #ifdef MYSQL_SERVER uint binlog_unsafe_map[256]; diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 649f8ec11fc..b4bf45116c4 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -3104,6 +3104,7 @@ public: LEX_STRING dbname, LEX_STRING name); bool init_default_internal_variable(struct sys_var_with_base *variable, LEX_STRING name); + bool set_variable(struct sys_var_with_base *variable, Item *item); void sp_variable_declarations_init(THD *thd, int nvars); bool sp_variable_declarations_finalize(THD *thd, int nvars, const Column_definition &cdef, diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index dcf88f5564e..c21d91004f2 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -14709,29 +14709,8 @@ option_value_following_option_type: option_value_no_option_type: internal_variable_name equal set_expr_or_default { - LEX *lex= Lex; - - if ($1.var == trg_new_row_fake_var) - { - /* We are in trigger and assigning value to field of new row */ - if (lex->set_trigger_new_row(&$1.base_name, $3)) - MYSQL_YYABORT; - } - else if ($1.var) - { - /* It is a system variable. */ - if (lex->set_system_variable(&$1, lex->option_type, $3)) - MYSQL_YYABORT; - } - else - { - sp_pcontext *spc= lex->spcont; - sp_variable *spv= spc->find_variable($1.base_name, false); - - /* It is a local variable. */ - if (lex->set_local_variable(spv, $3)) - MYSQL_YYABORT; - } + if (Lex->set_variable(&$1, $3)) + MYSQL_YYABORT; } | '@' ident_or_text equal expr { diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy index 672ab119343..3dac8c5a669 100644 --- a/sql/sql_yacc_ora.yy +++ b/sql/sql_yacc_ora.yy @@ -14599,25 +14599,9 @@ set_assign: } set_expr_or_default { - if ($1.var == trg_new_row_fake_var) - { - /* We are in trigger and assigning value to field of new row */ - if (Lex->set_trigger_new_row(&$1.base_name, $4) || - Lex->sphead->restore_lex(thd)) - MYSQL_YYABORT; - } - else - { - sp_pcontext *spc= Lex->spcont; - sp_variable *spv= spc->find_variable($1.base_name, false); - - /* It is a local variable. */ - if (Lex->set_local_variable(spv, $4)) - MYSQL_YYABORT; - - if (sp_create_assignment_instr(thd, yychar == YYEMPTY)) - MYSQL_YYABORT; - } + if (Lex->set_variable(&$1, $4) || + sp_create_assignment_instr(thd, yychar == YYEMPTY)) + MYSQL_YYABORT; } ; @@ -14755,29 +14739,8 @@ option_value_following_option_type: option_value_no_option_type: internal_variable_name equal set_expr_or_default { - LEX *lex= Lex; - - if ($1.var == trg_new_row_fake_var) - { - /* We are in trigger and assigning value to field of new row */ - if (lex->set_trigger_new_row(&$1.base_name, $3)) - MYSQL_YYABORT; - } - else if ($1.var) - { - /* It is a system variable. */ - if (lex->set_system_variable(&$1, lex->option_type, $3)) - MYSQL_YYABORT; - } - else - { - sp_pcontext *spc= lex->spcont; - sp_variable *spv= spc->find_variable($1.base_name, false); - - /* It is a local variable. */ - if (lex->set_local_variable(spv, $3)) - MYSQL_YYABORT; - } + if (Lex->set_variable(&$1, $3)) + MYSQL_YYABORT; } | '@' ident_or_text equal expr {