From 3e8a5e1d34cf9e83a2ed9bdfc9c6fc74c76a5ec4 Mon Sep 17 00:00:00 2001
From: "bell@sanja.is.com.ua" <>
Date: Thu, 31 Oct 2002 02:11:59 +0200
Subject: [PATCH] IN subselect with ORDER BY, HAVING & sum functions

---
 mysql-test/r/subselect.result | 11 +++++++++++
 mysql-test/t/subselect.test   |  5 +++++
 sql/item.h                    | 10 ++++------
 sql/item_subselect.cc         | 29 ++++++++++++++++++++++-------
 sql/item_sum.cc               |  7 +++++--
 sql/item_sum.h                | 11 ++++++++---
 sql/sql_lex.cc                |  3 ++-
 sql/sql_lex.h                 |  1 +
 8 files changed, 58 insertions(+), 19 deletions(-)

diff --git a/mysql-test/r/subselect.result b/mysql-test/r/subselect.result
index cccdd05f9b..1bbc652426 100644
--- a/mysql-test/r/subselect.result
+++ b/mysql-test/r/subselect.result
@@ -230,4 +230,15 @@ id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 1	PRIMARY	searchconthardwarefr3	index	NULL	topic	3	NULL	2	Using index
 2	SUBSELECT								No tables used
 3	UNION								No tables used
+SELECT 1 IN (SELECT 1 FROM searchconthardwarefr3 HAVING a);
+Unknown column 'a' in 'having clause'
+SELECT * from searchconthardwarefr3 where topic IN (SELECT topic FROM searchconthardwarefr3 GROUP BY date);
+topic	date	pseudo
+40143	2002-08-03	joce
+43506	2002-10-02	joce
+SELECT * from searchconthardwarefr3 where topic IN (SELECT topic FROM searchconthardwarefr3 GROUP BY date HAVING topic < 4100);
+topic	date	pseudo
+43506	2002-10-02	joce
+SELECT * from searchconthardwarefr3 where topic IN (SELECT SUM(topic) FROM searchconthardwarefr3);
+topic	date	pseudo
 drop table searchconthardwarefr3;
diff --git a/mysql-test/t/subselect.test b/mysql-test/t/subselect.test
index 0cf976b4be..5e868aaa67 100644
--- a/mysql-test/t/subselect.test
+++ b/mysql-test/t/subselect.test
@@ -120,4 +120,9 @@ SELECT 1 FROM searchconthardwarefr3 WHERE 1=(SELECT 1 UNION SELECT 1) UNION ALL
 -- error 1240
 SELECT 1 FROM searchconthardwarefr3 WHERE 1=(SELECT 1 UNION ALL SELECT 1) UNION SELECT 1;
 EXPLAIN SELECT 1 FROM searchconthardwarefr3 WHERE 1=(SELECT 1 UNION SELECT 1);
+-- error 1054
+SELECT 1 IN (SELECT 1 FROM searchconthardwarefr3 HAVING a);
+SELECT * from searchconthardwarefr3 where topic IN (SELECT topic FROM searchconthardwarefr3 GROUP BY date);
+SELECT * from searchconthardwarefr3 where topic IN (SELECT topic FROM searchconthardwarefr3 GROUP BY date HAVING topic < 4100);
+SELECT * from searchconthardwarefr3 where topic IN (SELECT SUM(topic) FROM searchconthardwarefr3);
 drop table searchconthardwarefr3;
\ No newline at end of file
diff --git a/sql/item.h b/sql/item.h
index 2b92d7c9ed..391ec347b7 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -116,11 +116,10 @@ public:
 */
 class Item_outer_select_context_saver :public Item_wrapper
 {
-  Item *item;
 public:
-  Item_outer_select_context_saver(Item *i):
-    item(i)
+  Item_outer_select_context_saver(Item *i)
   {
+    item= i;
   }
   bool fix_fields(THD *, struct st_table_list *, Item ** ref);
 };
@@ -130,11 +129,10 @@ public:
 */
 class Item_asterisk_remover :public Item_wrapper
 {
-  Item *item;
 public:
-  Item_asterisk_remover(Item *i):
-    item(i)
+  Item_asterisk_remover(Item *i)
   {
+    item= i;
   }
   bool fix_fields(THD *, struct st_table_list *, Item ** ref);
 };
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index f68af3079d..2f7c7aad9a 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -254,15 +254,30 @@ void Item_in_subselect::select_transformer(st_select_lex *select_lex,
     }
     else
       item= (Item*) sl->item_list.pop();
-    sl->item_list.empty();
-    sl->item_list.push_back(new Item_int(1));
+
     left_expr= new Item_outer_select_context_saver(left_expr);
-    item= new Item_asterisk_remover(item);
-    if (sl->where)
-      sl->where= new Item_cond_and(sl->where,
-				   new Item_func_eq(item, left_expr));
+
+    if (sl->having || sl->with_sum_func || sl->group_list.first)
+    {
+      sl->item_list.push_back(item);
+      item= new Item_ref(sl->item_list.head_ref(), 0, "<result>");
+      if (sl->having)
+	sl->having= new Item_cond_and(sl->having, 
+				      new Item_func_eq(item, left_expr));
+      else
+	sl->having= new Item_func_eq(item, left_expr);
+    }
     else
-      sl->where= new Item_func_eq(item, left_expr);
+    {
+      sl->item_list.empty();
+      sl->item_list.push_back(new Item_int(1));
+      item= new Item_asterisk_remover(item);
+      if (sl->where)
+	sl->where= new Item_cond_and(sl->where,
+				     new Item_func_eq(item, left_expr));
+      else
+	sl->where= new Item_func_eq(item, left_expr);
+    }
   }
   DBUG_VOID_RETURN;
 }
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index ae1a86845b..0b1150cb69 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -23,7 +23,6 @@
 
 #include "mysql_priv.h"
 
-
 Item_sum::Item_sum(List<Item> &list)
 {
   arg_count=list.elements;
@@ -38,10 +37,14 @@ Item_sum::Item_sum(List<Item> &list)
       args[i++]= item;
     }
   }
-  with_sum_func=1;
+  mark_as_sum_func();
   list.empty();					// Fields are used
 }
 
+void Item_sum::mark_as_sum_func()
+{
+  current_thd->lex.select->with_sum_func= with_sum_func= 1;
+}
 
 void Item_sum::make_field(Send_field *tmp_field)
 {
diff --git a/sql/item_sum.h b/sql/item_sum.h
index 3e67f1e362..a169a0ee56 100644
--- a/sql/item_sum.h
+++ b/sql/item_sum.h
@@ -34,23 +34,28 @@ public:
   uint arg_count;
   bool quick_group;			/* If incremental update of fields */
 
-  Item_sum() : arg_count(0),quick_group(1) { with_sum_func=1; }
+  Item_sum() : arg_count(0),quick_group(1) 
+  {
+    mark_as_sum_func();
+  }
   Item_sum(Item *a) :quick_group(1)
   {
     arg_count=1;
     args=tmp_args;
     args[0]=a;
-    with_sum_func = 1;
+    mark_as_sum_func();
   }
   Item_sum( Item *a, Item *b ) :quick_group(1)
   {
     arg_count=2;
     args=tmp_args;
     args[0]=a; args[1]=b;
-    with_sum_func=1;
+    mark_as_sum_func();
   }
   Item_sum(List<Item> &list);
   ~Item_sum() { result_field=0; }
+  inline void mark_as_sum_func();
+
   enum Type type() const { return SUM_FUNC_ITEM; }
   virtual enum Sumfunctype sum_func () const=0;
   virtual void reset()=0;
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 52f1be6bdd..31f7e99a2b 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -934,7 +934,8 @@ void st_select_lex_node::init_select()
   order_list.first= 0;
   order_list.next= (byte**) &order_list.first;
   select_limit= HA_POS_ERROR;
-  offset_limit= 0; 
+  offset_limit= 0;
+  with_sum_func= 0;
 }
 
 void st_select_lex_unit::init_query()
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 50bff7c7f6..64186fb49e 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -196,6 +196,7 @@ public:
   enum sub_select_type linkage;
   SQL_LIST order_list;                /* ORDER clause */
   ha_rows select_limit, offset_limit; /* LIMIT clause parameters */
+  bool with_sum_func;
   void init_query();
   void init_select();
   void include_down(st_select_lex_node *upper);
-- 
2.30.9