From 0e74ac50285b15fae7fda70a809c9b42027e88c2 Mon Sep 17 00:00:00 2001
From: Alexey Kopytov <Alexey.Kopytov@Sun.com>
Date: Tue, 24 Aug 2010 14:35:48 +0400
Subject: [PATCH] Bug #55568: user variable assignments crash server when used 
            within query

The server could crash after materializing a derived table
which requires a temporary table for grouping.

When destroying the temporary table used to execute a query for
a derived table, JOIN::destroy() did not clean up Item_fields
pointing to fields in the temporary table. This led to
dereferencing a dangling pointer when printing out the items
tree later in the outer SELECT.

The solution is an addendum to the patch for bug37362: in
addition to cleaning up items in tmp_all_fields3, do the same
for items in tmp_all_fields1, since now we have an example
where this is necessary.
---
 mysql-test/r/join.result | 51 ++++++++++++++++++++++++++++++++++++++++
 mysql-test/t/join.test   | 46 ++++++++++++++++++++++++++++++++++++
 sql/field.cc             |  2 +-
 sql/sql_select.cc        | 22 +++++++++++------
 sql/sql_select.h         |  1 +
 5 files changed, 114 insertions(+), 8 deletions(-)

diff --git a/mysql-test/r/join.result b/mysql-test/r/join.result
index c60c6bfb3c8..c3c292b2106 100644
--- a/mysql-test/r/join.result
+++ b/mysql-test/r/join.result
@@ -1184,4 +1184,55 @@ NULL
 NULL
 1
 DROP TABLE t1, t2, mm1;
+#
+# Bug #55568: user variable assignments crash server when used within
+#             query
+#
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES (0), (1);
+SELECT MULTIPOINT(
+1,
+(
+SELECT MULTIPOINT(
+MULTIPOINT(
+1,
+(SELECT COUNT(*) FROM (SELECT 1 FROM t1 GROUP BY a,a) d)
+)
+) FROM t1
+)
+) != COUNT(*) q FROM t1 GROUP BY a;
+q
+NULL
+NULL
+SELECT MULTIPOINT(
+1,
+(
+SELECT MULTIPOINT(
+MULTIPOINT(
+1,
+(SELECT COUNT(*) FROM (SELECT 1 FROM t1 GROUP BY a,a) d)
+)
+) FROM t1
+)
+) != COUNT(*) q FROM t1 GROUP BY a;
+q
+NULL
+NULL
+DROP TABLE t1;
+#
+# Bug #54468: crash after item's print() function when ordering/grouping 
+#             by subquery
+#
+CREATE TABLE t1(a INT, b INT);
+INSERT INTO t1 VALUES (), ();
+SELECT 1 FROM t1
+GROUP BY
+GREATEST(t1.a,
+(SELECT 1 FROM
+(SELECT t1.b FROM t1,t1 t2
+ORDER BY t1.a, t1.a LIMIT 1) AS d)
+);
+1
+1
+DROP TABLE t1;
 End of 5.1 tests
diff --git a/mysql-test/t/join.test b/mysql-test/t/join.test
index 43b373c9703..6969be6fdc4 100644
--- a/mysql-test/t/join.test
+++ b/mysql-test/t/join.test
@@ -851,4 +851,50 @@ ENGINE=MERGE  UNION=(t1,t2);
 SELECT t1.a FROM mm1,t1;
 DROP TABLE t1, t2, mm1;
 
+--echo #
+--echo # Bug #55568: user variable assignments crash server when used within
+--echo #             query
+--echo #
+
+CREATE TABLE t1 (a INT);
+
+INSERT INTO t1 VALUES (0), (1);
+
+let $i=2;
+while ($i)
+{
+  SELECT MULTIPOINT(
+    1,
+    (
+      SELECT MULTIPOINT(
+        MULTIPOINT(
+          1,
+          (SELECT COUNT(*) FROM (SELECT 1 FROM t1 GROUP BY a,a) d)
+        )
+      ) FROM t1
+    )
+  ) != COUNT(*) q FROM t1 GROUP BY a;
+  dec $i;
+}
+
+DROP TABLE t1;
+
+--echo #
+--echo # Bug #54468: crash after item's print() function when ordering/grouping 
+--echo #             by subquery
+--echo #
+
+CREATE TABLE t1(a INT, b INT);
+INSERT INTO t1 VALUES (), ();
+
+SELECT 1 FROM t1
+GROUP BY
+GREATEST(t1.a,
+         (SELECT 1 FROM
+          (SELECT t1.b FROM t1,t1 t2
+           ORDER BY t1.a, t1.a LIMIT 1) AS d)
+        );
+
+DROP TABLE t1;
+
 --echo End of 5.1 tests
diff --git a/sql/field.cc b/sql/field.cc
index c887a5f1c9b..619e6a780da 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -1535,7 +1535,7 @@ void Field::make_field(Send_field *field)
   }
   else
     field->org_table_name= field->db_name= "";
-  if (orig_table)
+  if (orig_table && orig_table->alias)
   {
     field->table_name= orig_table->alias;
     field->org_col_name= field_name;
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 2fc287bbe66..fc137f5fd90 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -2378,13 +2378,8 @@ JOIN::destroy()
 
   cleanup(1);
  /* Cleanup items referencing temporary table columns */
-  if (!tmp_all_fields3.is_empty())
-  {
-    List_iterator_fast<Item> it(tmp_all_fields3);
-    Item *item;
-    while ((item= it++))
-      item->cleanup();
-  }
+  cleanup_item_list(tmp_all_fields1);
+  cleanup_item_list(tmp_all_fields3);
   if (exec_tmp_table1)
     free_tmp_table(thd, exec_tmp_table1);
   if (exec_tmp_table2)
@@ -2395,6 +2390,19 @@ JOIN::destroy()
   DBUG_RETURN(error);
 }
 
+
+void JOIN::cleanup_item_list(List<Item> &items) const
+{
+  if (!items.is_empty())
+  {
+    List_iterator_fast<Item> it(items);
+    Item *item;
+    while ((item= it++))
+      item->cleanup();
+  }
+}
+
+
 /**
   An entry point to single-unit select (a select without UNION).
 
diff --git a/sql/sql_select.h b/sql/sql_select.h
index b39827ef61b..007dc91957c 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -577,6 +577,7 @@ class JOIN :public Sql_alloc
   */
   bool implicit_grouping; 
   bool make_simple_join(JOIN *join, TABLE *tmp_table);
+  void cleanup_item_list(List<Item> &items) const;
 };
 
 
-- 
2.30.9