From 4ab4631b068587756e247652d000e87bdb460d1a Mon Sep 17 00:00:00 2001
From: unknown <aelkin@mysql.com>
Date: Fri, 5 May 2006 11:21:21 +0300
Subject: [PATCH] Bug#19136: Crashing log-bin and uninitialized user variables
 in a derived table

The reason of the bug is in that `get_var_with_binlog' performs missed
assingment of
the variables as side-effect. Doing that it eventually calls
`free_underlaid_joins' to pass as an argument `thd->lex->select_lex' of the lex
which belongs to the user query, not
to one which is emulated i.e SET @var1:=NULL.


`get_var_with_binlog' is refined to supply a temporary lex to sql_set_variables's stack.


mysql-test/r/rpl_user_variables.result:
  results changed
mysql-test/t/rpl_user_variables.test:
  a problematic query to be binlogged is added
sql/item_func.cc:
  BUG#19136: Crashing log-bin and uninitialized user variables

  The reason of the bug is in that how `get_var_with_binlog' performs missed
  assingment of the variables: `free_underlaid_joins' gets as an argument `thd->lex->select_lex'
  which belongs to the user query, not to one which is emulated i.e SET @var1:=NULL.

  `get_var_with_binlog' is refined to supply a temporary lex to sql_set_variables's stack.
---
 mysql-test/r/rpl_user_variables.result |  1 +
 mysql-test/t/rpl_user_variables.test   |  6 ++++++
 sql/item_func.cc                       | 10 ++++++++++
 3 files changed, 17 insertions(+)

diff --git a/mysql-test/r/rpl_user_variables.result b/mysql-test/r/rpl_user_variables.result
index 85768270ba3..8af2c3e0b22 100644
--- a/mysql-test/r/rpl_user_variables.result
+++ b/mysql-test/r/rpl_user_variables.result
@@ -105,5 +105,6 @@ slave-bin.000001	1370	User var	2	1370	@`a`=5
 slave-bin.000001	1412	Query	1	1412	use `test`; insert into t1 values (@a),(@a)
 slave-bin.000001	1478	User var	2	1478	@`a`=NULL
 slave-bin.000001	1503	Query	1	1503	use `test`; insert into t1 values (@a),(@a),(@a*5)
+insert into t1 select * FROM (select @var1 union  select @var2) AS t2;
 drop table t1;
 stop slave;
diff --git a/mysql-test/t/rpl_user_variables.test b/mysql-test/t/rpl_user_variables.test
index 5cf502e05bd..6597413c22e 100644
--- a/mysql-test/t/rpl_user_variables.test
+++ b/mysql-test/t/rpl_user_variables.test
@@ -47,9 +47,15 @@ connection slave;
 sync_with_master;
 select * from t1;
 show binlog events from 141;
+
+#
+# BUG19136: Crashing log-bin and uninitialized user variables in a derived table
+# just to check nothing bad happens anymore
 connection master;
+insert into t1 select * FROM (select @var1 union  select @var2) AS t2;
 drop table t1;
 save_master_pos;
+
 connection slave;
 sync_with_master;
 stop slave;
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 174a8c55d01..15e272cdef8 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -2733,14 +2733,24 @@ int get_var_with_binlog(THD *thd, LEX_STRING &name,
       sql_set_variables(), we could instead manually call check() and update();
       this would save memory and time; but calling sql_set_variables() makes
       one unique place to maintain (sql_set_variables()). 
+
+      Manipulation with lex is necessary since free_underlaid_joins
+      is going to release memory belonging to the main query.
     */
 
     List<set_var_base> tmp_var_list;
+    LEX *sav_lex= thd->lex, lex_tmp;
+    thd->lex= &lex_tmp;
+    lex_start(thd, NULL, 0);
     tmp_var_list.push_back(new set_var_user(new Item_func_set_user_var(name,
                                                                        new Item_null())));
     /* Create the variable */
     if (sql_set_variables(thd, &tmp_var_list))
+    {
+      thd->lex= sav_lex;
       goto err;
+    }
+    thd->lex= sav_lex;
     if (!(var_entry= get_variable(&thd->user_vars, name, 0)))
       goto err;
   }