Commit fa612924 authored by Martin Hansson's avatar Martin Hansson

Merge of fix for Bug#48459

parents 185e24d5 8e53e7e4
...@@ -4335,7 +4335,7 @@ com_status(String *buffer __attribute__((unused)), ...@@ -4335,7 +4335,7 @@ com_status(String *buffer __attribute__((unused)),
Don't remove "limit 1", Don't remove "limit 1",
it is protection againts SQL_SELECT_LIMIT=0 it is protection againts SQL_SELECT_LIMIT=0
*/ */
if (mysql_store_result_for_lazy(&result)) if (!mysql_store_result_for_lazy(&result))
{ {
MYSQL_ROW cur=mysql_fetch_row(result); MYSQL_ROW cur=mysql_fetch_row(result);
if (cur) if (cur)
...@@ -4379,7 +4379,7 @@ com_status(String *buffer __attribute__((unused)), ...@@ -4379,7 +4379,7 @@ com_status(String *buffer __attribute__((unused)),
if (mysql_errno(&mysql) == CR_SERVER_GONE_ERROR) if (mysql_errno(&mysql) == CR_SERVER_GONE_ERROR)
return 0; return 0;
} }
if (mysql_store_result_for_lazy(&result)) if (!mysql_store_result_for_lazy(&result))
{ {
MYSQL_ROW cur=mysql_fetch_row(result); MYSQL_ROW cur=mysql_fetch_row(result);
if (cur) if (cur)
......
#
# Bug#47671 - wrong character-set after upgrade from 5.1.34 to 5.1.39
#
# Extract only charset information from 'status' command output using regex
--------------
Server characterset: utf8
Db characterset: utf8
Client characterset: utf8
Conn. characterset: utf8
--------------
...@@ -6979,6 +6979,64 @@ CALL p1; ...@@ -6979,6 +6979,64 @@ CALL p1;
ERROR 42S22: Unknown column 'A.b' in 'IN/ALL/ANY subquery' ERROR 42S22: Unknown column 'A.b' in 'IN/ALL/ANY subquery'
DROP PROCEDURE p1; DROP PROCEDURE p1;
DROP TABLE t1, t2; DROP TABLE t1, t2;
#
# Bug#47627: SET @@{global.session}.local_variable in stored routine causes crash
# Bug#48626: Crash or lost connection using SET for declared variables with @@
#
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 init_connect INT DEFAULT 0;
SET init_connect= 10;
SET @@GLOBAL.init_connect= 'SELECT 1';
SET @@SESSION.IDENTITY= 1;
SELECT @@SESSION.IDENTITY;
SELECT @@GLOBAL.init_connect;
SELECT init_connect;
END//
CREATE PROCEDURE p6()
BEGIN
DECLARE v INT DEFAULT 0;
SET @@v= 0;
END//
ERROR HY000: Unknown system variable 'v'
SET @old_init_connect= @@GLOBAL.init_connect;
CALL p5();
@@SESSION.IDENTITY
1
@@GLOBAL.init_connect
SELECT 1
init_connect
10
SET @@GLOBAL.init_connect= @old_init_connect;
DROP PROCEDURE p2;
DROP PROCEDURE p5;
# ------------------------------------------------------------------ # ------------------------------------------------------------------
# -- End of 5.1 tests # -- End of 5.1 tests
# ------------------------------------------------------------------ # ------------------------------------------------------------------
--default-character-set=utf8 --skip-character-set-client-handshake
--echo #
--echo # Bug#47671 - wrong character-set after upgrade from 5.1.34 to 5.1.39
--echo #
--echo # Extract only charset information from 'status' command output using regex
--replace_regex /.*mysql.*// /Connection.*// /Current.*// /SSL.*// /Using.*// /Server version.*// /Protocol.*// /UNIX.*// /Uptime.*// /Threads.*//
--exec $MYSQL -u root test -e "status";
...@@ -8263,6 +8263,73 @@ CALL p1; ...@@ -8263,6 +8263,73 @@ CALL p1;
DROP PROCEDURE p1; DROP PROCEDURE p1;
DROP TABLE t1, t2; DROP TABLE t1, t2;
--echo #
--echo # Bug#47627: SET @@{global.session}.local_variable in stored routine causes crash
--echo # Bug#48626: Crash or lost connection using SET for declared variables with @@
--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 init_connect INT DEFAULT 0;
SET init_connect= 10;
SET @@GLOBAL.init_connect= 'SELECT 1';
SET @@SESSION.IDENTITY= 1;
SELECT @@SESSION.IDENTITY;
SELECT @@GLOBAL.init_connect;
SELECT init_connect;
END//
--error ER_UNKNOWN_SYSTEM_VARIABLE
CREATE PROCEDURE p6()
BEGIN
DECLARE v INT DEFAULT 0;
SET @@v= 0;
END//
delimiter ;//
SET @old_init_connect= @@GLOBAL.init_connect;
CALL p5();
SET @@GLOBAL.init_connect= @old_init_connect;
DROP PROCEDURE p2;
DROP PROCEDURE p5;
--echo # ------------------------------------------------------------------ --echo # ------------------------------------------------------------------
--echo # -- End of 5.1 tests --echo # -- End of 5.1 tests
......
...@@ -960,12 +960,23 @@ int Arg_comparator::set_cmp_func(Item_result_field *owner_arg, ...@@ -960,12 +960,23 @@ int Arg_comparator::set_cmp_func(Item_result_field *owner_arg,
(*b)->field_type() == MYSQL_TYPE_YEAR)) (*b)->field_type() == MYSQL_TYPE_YEAR))
{ {
is_nulls_eq= is_owner_equal_func(); is_nulls_eq= is_owner_equal_func();
year_as_datetime= FALSE;
if ((*a)->is_datetime()) if ((*a)->is_datetime())
{ {
year_as_datetime= TRUE; year_as_datetime= TRUE;
get_value_a_func= &get_datetime_value; get_value_a_func= &get_datetime_value;
} else if ((*a)->field_type() == MYSQL_TYPE_YEAR) } else if ((*a)->field_type() == MYSQL_TYPE_YEAR)
get_value_a_func= &get_year_value; get_value_a_func= &get_year_value;
else
{
/*
Because convert_constant_item is called only for EXECUTE in PS mode
the value of get_value_x_func set in PREPARE might be not
valid for EXECUTE.
*/
get_value_a_func= NULL;
}
if ((*b)->is_datetime()) if ((*b)->is_datetime())
{ {
...@@ -973,6 +984,8 @@ int Arg_comparator::set_cmp_func(Item_result_field *owner_arg, ...@@ -973,6 +984,8 @@ int Arg_comparator::set_cmp_func(Item_result_field *owner_arg,
get_value_b_func= &get_datetime_value; get_value_b_func= &get_datetime_value;
} else if ((*b)->field_type() == MYSQL_TYPE_YEAR) } else if ((*b)->field_type() == MYSQL_TYPE_YEAR)
get_value_b_func= &get_year_value; get_value_b_func= &get_year_value;
else
get_value_b_func= NULL;
func= &Arg_comparator::compare_year; func= &Arg_comparator::compare_year;
return 0; return 0;
......
...@@ -389,6 +389,138 @@ void case_stmt_action_end_case(LEX *lex, bool simple) ...@@ -389,6 +389,138 @@ void case_stmt_action_end_case(LEX *lex, bool simple)
lex->sphead->do_cont_backpatch(); lex->sphead->do_cont_backpatch();
} }
static bool
find_sys_var_null_base(THD *thd, struct sys_var_with_base *tmp)
{
tmp->var= find_sys_var(thd, tmp->base_name.str, tmp->base_name.length);
if (tmp->var == NULL)
my_error(ER_UNKNOWN_SYSTEM_VARIABLE, MYF(0), tmp->base_name.str);
else
tmp->base_name= null_lex_str;
return thd->is_error();
}
/**
Helper action for a SET statement.
Used to push a system variable into the assignment list.
@param thd the current thread
@param tmp the system variable with base name
@param var_type the scope of the variable
@param val the value being assigned to the variable
@return TRUE if error, FALSE otherwise.
*/
static bool
set_system_variable(THD *thd, struct sys_var_with_base *tmp,
enum enum_var_type var_type, Item *val)
{
set_var *var;
LEX *lex= thd->lex;
/* No AUTOCOMMIT from a stored function or trigger. */
if (lex->spcont && tmp->var == &sys_autocommit)
lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT;
if (! (var= new set_var(var_type, tmp->var, &tmp->base_name, val)))
return TRUE;
return lex->var_list.push_back(var);
}
/**
Helper action for a SET statement.
Used to push a SP local variable into the assignment list.
@param thd the current thread
@param var_type the SP local variable
@param val the value being assigned to the variable
@return TRUE if error, FALSE otherwise.
*/
static bool
set_local_variable(THD *thd, sp_variable_t *spv, Item *val)
{
Item *it;
LEX *lex= thd->lex;
sp_instr_set *sp_set;
if (val)
it= val;
else if (spv->dflt)
it= spv->dflt;
else
{
it= new (thd->mem_root) Item_null();
if (it == NULL)
return TRUE;
}
sp_set= new sp_instr_set(lex->sphead->instructions(), lex->spcont,
spv->offset, it, spv->type, lex, TRUE);
return (sp_set == NULL || lex->sphead->add_instr(sp_set));
}
/**
Helper action for a SET statement.
Used to SET a field of NEW row.
@param thd the current thread
@param name the field name
@param val the value being assigned to the row
@return TRUE if error, FALSE otherwise.
*/
static bool
set_trigger_new_row(THD *thd, LEX_STRING *name, Item *val)
{
LEX *lex= thd->lex;
Item_trigger_field *trg_fld;
sp_instr_set_trigger_field *sp_fld;
/* QQ: Shouldn't this be field's default value ? */
if (! val)
val= new Item_null();
DBUG_ASSERT(lex->trg_chistics.action_time == TRG_ACTION_BEFORE &&
(lex->trg_chistics.event == TRG_EVENT_INSERT ||
lex->trg_chistics.event == TRG_EVENT_UPDATE));
trg_fld= new (thd->mem_root)
Item_trigger_field(lex->current_context(),
Item_trigger_field::NEW_ROW,
name->str, UPDATE_ACL, FALSE);
if (trg_fld == NULL)
return TRUE;
sp_fld= new sp_instr_set_trigger_field(lex->sphead->instructions(),
lex->spcont, trg_fld, val, lex);
if (sp_fld == NULL)
return TRUE;
/*
Let us add this item to list of all Item_trigger_field
objects in trigger.
*/
lex->trg_table_fields.link_in_list((uchar *) trg_fld,
(uchar **) &trg_fld->next_trg_field);
return lex->sphead->add_instr(sp_fld);
}
/** /**
Helper to resolve the SQL:2003 Syntax exception 1) in <in predicate>. Helper to resolve the SQL:2003 Syntax exception 1) in <in predicate>.
See SQL:2003, Part 2, section 8.4 <in predicate>, Note 184, page 383. See SQL:2003, Part 2, section 8.4 <in predicate>, Note 184, page 383.
...@@ -11830,98 +11962,42 @@ sys_option_value: ...@@ -11830,98 +11962,42 @@ sys_option_value:
option_type internal_variable_name equal set_expr_or_default option_type internal_variable_name equal set_expr_or_default
{ {
THD *thd= YYTHD; THD *thd= YYTHD;
LEX *lex=Lex; LEX *lex= Lex;
LEX_STRING *name= &$2.base_name;
if ($2.var == trg_new_row_fake_var) if ($2.var == trg_new_row_fake_var)
{ {
/* We are in trigger and assigning value to field of new row */ /* We are in trigger and assigning value to field of new row */
Item *it;
Item_trigger_field *trg_fld;
sp_instr_set_trigger_field *sp_fld;
LINT_INIT(sp_fld);
if ($1) if ($1)
{ {
my_parse_error(ER(ER_SYNTAX_ERROR)); my_parse_error(ER(ER_SYNTAX_ERROR));
MYSQL_YYABORT; MYSQL_YYABORT;
} }
if ($4) if (set_trigger_new_row(YYTHD, name, $4))
it= $4;
else
{
/* QQ: Shouldn't this be field's default value ? */
it= new Item_null();
}
DBUG_ASSERT(lex->trg_chistics.action_time == TRG_ACTION_BEFORE &&
(lex->trg_chistics.event == TRG_EVENT_INSERT ||
lex->trg_chistics.event == TRG_EVENT_UPDATE));
trg_fld= new (thd->mem_root)
Item_trigger_field(Lex->current_context(),
Item_trigger_field::NEW_ROW,
$2.base_name.str,
UPDATE_ACL, FALSE);
if (trg_fld == NULL)
MYSQL_YYABORT;
sp_fld= new sp_instr_set_trigger_field(lex->sphead->
instructions(),
lex->spcont,
trg_fld,
it, lex);
if (sp_fld == NULL)
MYSQL_YYABORT;
/*
Let us add this item to list of all Item_trigger_field
objects in trigger.
*/
lex->trg_table_fields.link_in_list((uchar *)trg_fld,
(uchar **) &trg_fld->
next_trg_field);
if (lex->sphead->add_instr(sp_fld))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
else if ($2.var) else if ($2.var)
{ /* System variable */ {
if ($1) if ($1)
lex->option_type= $1; lex->option_type= $1;
set_var *var= new set_var(lex->option_type, $2.var,
&$2.base_name, $4); /* It is a system variable. */
if (var == NULL) if (set_system_variable(thd, &$2, lex->option_type, $4))
MYSQL_YYABORT; MYSQL_YYABORT;
lex->var_list.push_back(var);
} }
else else
{ {
/* An SP local variable */ sp_pcontext *spc= lex->spcont;
sp_pcontext *ctx= lex->spcont; sp_variable_t *spv= spc->find_variable(name);
sp_variable_t *spv;
sp_instr_set *sp_set;
Item *it;
if ($1) if ($1)
{ {
my_parse_error(ER(ER_SYNTAX_ERROR)); my_parse_error(ER(ER_SYNTAX_ERROR));
MYSQL_YYABORT; MYSQL_YYABORT;
} }
spv= ctx->find_variable(&$2.base_name); /* It is a local variable. */
if (set_local_variable(thd, spv, $4))
if ($4)
it= $4;
else if (spv->dflt)
it= spv->dflt;
else
{
it= new (thd->mem_root) Item_null();
if (it == NULL)
MYSQL_YYABORT;
}
sp_set= new sp_instr_set(lex->sphead->instructions(), ctx,
spv->offset, it, spv->type, lex, TRUE);
if (sp_set == NULL ||
lex->sphead->add_instr(sp_set))
MYSQL_YYABORT; MYSQL_YYABORT;
} }
} }
...@@ -11957,11 +12033,16 @@ option_value: ...@@ -11957,11 +12033,16 @@ option_value:
} }
| '@' '@' opt_var_ident_type internal_variable_name equal set_expr_or_default | '@' '@' opt_var_ident_type internal_variable_name equal set_expr_or_default
{ {
LEX *lex=Lex; THD *thd= YYTHD;
set_var *var= new set_var($3, $4.var, &$4.base_name, $6); struct sys_var_with_base tmp= $4;
if (var == NULL) /* Lookup if necessary: must be a system variable. */
if (tmp.var == NULL)
{
if (find_sys_var_null_base(thd, &tmp))
MYSQL_YYABORT;
}
if (set_system_variable(thd, &tmp, $3, $6))
MYSQL_YYABORT; MYSQL_YYABORT;
lex->var_list.push_back(var);
} }
| charset old_or_new_charset_name_or_default | charset old_or_new_charset_name_or_default
{ {
...@@ -12054,31 +12135,26 @@ internal_variable_name: ...@@ -12054,31 +12135,26 @@ internal_variable_name:
ident ident
{ {
THD *thd= YYTHD; THD *thd= YYTHD;
LEX *lex= thd->lex; sp_pcontext *spc= thd->lex->spcont;
sp_pcontext *spc= lex->spcont;
sp_variable_t *spv; sp_variable_t *spv;
/* We have to lookup here since local vars can shadow sysvars */ /* Best effort lookup for system variable. */
if (!spc || !(spv = spc->find_variable(&$1))) if (!spc || !(spv = spc->find_variable(&$1)))
{ {
struct sys_var_with_base tmp= {NULL, $1};
/* Not an SP local variable */ /* Not an SP local variable */
sys_var *tmp=find_sys_var(thd, $1.str, $1.length); if (find_sys_var_null_base(thd, &tmp))
if (!tmp)
MYSQL_YYABORT; MYSQL_YYABORT;
$$.var= tmp;
$$.base_name= null_lex_str; $$= tmp;
if (spc && tmp == &sys_autocommit)
{
/*
We don't allow setting AUTOCOMMIT from a stored function
or trigger.
*/
lex->sphead->m_flags|= sp_head::HAS_SET_AUTOCOMMIT_STMT;
}
} }
else else
{ {
/* An SP local variable */ /*
Possibly an SP local variable (or a shadowed sysvar).
Will depend on the context of the SET statement.
*/
$$.var= NULL; $$.var= NULL;
$$.base_name= $1; $$.base_name= $1;
} }
......
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