diff --git a/client/mysql.cc b/client/mysql.cc
index 4f9aef411ca17754f2a43c5059490d90954096dd..9d078153a333b7542708bb095ef4f55581f0834d 100644
--- a/client/mysql.cc
+++ b/client/mysql.cc
@@ -4335,7 +4335,7 @@ com_status(String *buffer __attribute__((unused)),
     Don't remove "limit 1",
     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);
     if (cur)
@@ -4379,7 +4379,7 @@ com_status(String *buffer __attribute__((unused)),
     if (mysql_errno(&mysql) == CR_SERVER_GONE_ERROR)
       return 0;
   }
-  if (mysql_store_result_for_lazy(&result))
+  if (!mysql_store_result_for_lazy(&result))
   {
     MYSQL_ROW cur=mysql_fetch_row(result);
     if (cur)
diff --git a/mysql-test/r/bug47671.result b/mysql-test/r/bug47671.result
new file mode 100644
index 0000000000000000000000000000000000000000..2cff6f1b59cb561cb4e7791250a3c284d4f68bff
--- /dev/null
+++ b/mysql-test/r/bug47671.result
@@ -0,0 +1,13 @@
+#
+# 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
+
+--------------
+
diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result
index 67514c314f41ac21106fe3237ca6418f81a5eff6..83ad7545685855ad28f255f2fc0dc3745f8d4b5f 100644
--- a/mysql-test/r/sp.result
+++ b/mysql-test/r/sp.result
@@ -6979,6 +6979,64 @@ CALL p1;
 ERROR 42S22: Unknown column 'A.b' in 'IN/ALL/ANY subquery'
 DROP PROCEDURE p1;
 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
 # ------------------------------------------------------------------
diff --git a/mysql-test/t/bug47671-master.opt b/mysql-test/t/bug47671-master.opt
new file mode 100644
index 0000000000000000000000000000000000000000..0afdf49e0229de102c057cd4024f3e7ee6940c74
--- /dev/null
+++ b/mysql-test/t/bug47671-master.opt
@@ -0,0 +1 @@
+--default-character-set=utf8 --skip-character-set-client-handshake
diff --git a/mysql-test/t/bug47671.test b/mysql-test/t/bug47671.test
new file mode 100644
index 0000000000000000000000000000000000000000..3efff39ff588b42b938c289cebc482ee7d2a3de7
--- /dev/null
+++ b/mysql-test/t/bug47671.test
@@ -0,0 +1,6 @@
+--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";
diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test
index 44c4556340eabfb576777dfb657eb08e3034fe94..73ba62612b80ae606756ee2b1d5d42eddcf3dfe4 100644
--- a/mysql-test/t/sp.test
+++ b/mysql-test/t/sp.test
@@ -8263,6 +8263,73 @@ CALL p1;
 DROP PROCEDURE p1;
 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 # -- End of 5.1 tests
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 9662c0209c8851d7258502cc49b7839fe3146964..fd5eca8911a09ce351a969df7a4909d226d917ac 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -960,12 +960,23 @@ int Arg_comparator::set_cmp_func(Item_result_field *owner_arg,
              (*b)->field_type() == MYSQL_TYPE_YEAR))
   {
     is_nulls_eq= is_owner_equal_func();
+    year_as_datetime= FALSE;
+
     if ((*a)->is_datetime())
     {
       year_as_datetime= TRUE;
       get_value_a_func= &get_datetime_value;
     } else if ((*a)->field_type() == MYSQL_TYPE_YEAR)
       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())
     {
@@ -973,6 +984,8 @@ int Arg_comparator::set_cmp_func(Item_result_field *owner_arg,
       get_value_b_func= &get_datetime_value;
     } else if ((*b)->field_type() == MYSQL_TYPE_YEAR)
       get_value_b_func= &get_year_value;
+    else
+      get_value_b_func= NULL;
 
     func= &Arg_comparator::compare_year;
     return 0;
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 90bd7395732748e859898547abaeaa6bd1653fea..72b8aa32e3001f55f4d83ae4a4f4ce018b077f4c 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -389,6 +389,138 @@ void case_stmt_action_end_case(LEX *lex, bool simple)
   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>.
   See SQL:2003, Part 2, section 8.4 <in predicate>, Note 184, page 383.
@@ -11830,98 +11962,42 @@ sys_option_value:
           option_type internal_variable_name equal set_expr_or_default
           {
             THD *thd= YYTHD;
-            LEX *lex=Lex;
+            LEX *lex= Lex;
+            LEX_STRING *name= &$2.base_name;
 
             if ($2.var == trg_new_row_fake_var)
             {
               /* 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)
               {
                 my_parse_error(ER(ER_SYNTAX_ERROR));
                 MYSQL_YYABORT;
               }
-              if ($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))
+              if (set_trigger_new_row(YYTHD, name, $4))
                 MYSQL_YYABORT;
             }
             else if ($2.var)
-            { /* System variable */
+            {
               if ($1)
                 lex->option_type= $1;
-              set_var *var= new set_var(lex->option_type, $2.var,
-                                        &$2.base_name, $4);
-              if (var == NULL)
+
+              /* It is a system variable. */
+              if (set_system_variable(thd, &$2, lex->option_type, $4))
                 MYSQL_YYABORT;
-              lex->var_list.push_back(var);
             }
             else
             {
-              /* An SP local variable */
-              sp_pcontext *ctx= lex->spcont;
-              sp_variable_t *spv;
-              sp_instr_set *sp_set;
-              Item *it;
+              sp_pcontext *spc= lex->spcont;
+              sp_variable_t *spv= spc->find_variable(name);
+
               if ($1)
               {
                 my_parse_error(ER(ER_SYNTAX_ERROR));
                 MYSQL_YYABORT;
               }
 
-              spv= ctx->find_variable(&$2.base_name);
-
-              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))
+              /* It is a local variable. */
+              if (set_local_variable(thd, spv, $4))
                 MYSQL_YYABORT;
             }
           }
@@ -11957,11 +12033,16 @@ option_value:
           }
         | '@' '@' opt_var_ident_type internal_variable_name equal set_expr_or_default
           {
-            LEX *lex=Lex;
-            set_var *var= new set_var($3, $4.var, &$4.base_name, $6);
-            if (var == NULL)
+            THD *thd= YYTHD;
+            struct sys_var_with_base tmp= $4;
+            /* 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;
-            lex->var_list.push_back(var);
           }
         | charset old_or_new_charset_name_or_default
           {
@@ -12054,31 +12135,26 @@ internal_variable_name:
           ident
           {
             THD *thd= YYTHD;
-            LEX *lex= thd->lex;
-            sp_pcontext *spc= lex->spcont;
+            sp_pcontext *spc= thd->lex->spcont;
             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)))
             {
+              struct sys_var_with_base tmp= {NULL, $1};
+
               /* Not an SP local variable */
-              sys_var *tmp=find_sys_var(thd, $1.str, $1.length);
-              if (!tmp)
+              if (find_sys_var_null_base(thd, &tmp))
                 MYSQL_YYABORT;
-              $$.var= tmp;
-              $$.base_name= null_lex_str;
-              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;
-              }
+
+              $$= tmp;
             }
             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;
               $$.base_name= $1;
             }