From 3190b21f95e58886e1507384bf792ed68a9f8397 Mon Sep 17 00:00:00 2001
From: unknown <evgen@moonbone.local>
Date: Thu, 24 Nov 2005 19:16:51 +0300
Subject: [PATCH] Fix bug #14482 Wrongly applied optimization in
 resolve_const_item() caused crash

resolve_const_item() substitutes item which will evaluate to constant with
equvalent constant item, basing on the item's result type. In this case
subselect was resolved as constant, and resolve_const_item() was substituting
it's result's Item_caches to Item_null. Later Item_cache's function was called
for Item_null object, which caused server crash.

resolve_const_item() now substitutes constants for items with
result_type == ROW_RESULT only for Item_rows.


sql/item.cc:
  Fix bug #14482 Wrongly applied optimization in resolve_const_item() caused
  crash

  resolve_const_item() now applies optimization for items with
  result_type == ROW_RESULT only to Item_rows.
mysql-test/t/select.test:
  Test case for bug #14482 Wrongly applied optimization in resolve_const_item() caused crash
mysql-test/r/select.result:
  Test case for bug #14482 Wrongly applied optimization in resolve_const_item() caused crash
---
 mysql-test/r/select.result |  8 ++++++++
 mysql-test/t/select.test   | 11 +++++++++++
 sql/item.cc                | 15 ++++++++++++---
 3 files changed, 31 insertions(+), 3 deletions(-)

diff --git a/mysql-test/r/select.result b/mysql-test/r/select.result
index 64c329ee10..b80ca2b195 100644
--- a/mysql-test/r/select.result
+++ b/mysql-test/r/select.result
@@ -2706,3 +2706,11 @@ select distinct count(f2) >0 from t1 left join t2 on f1=f3 group by f1;
 count(f2) >0
 1
 drop table t1,t2;
+create table t1 (f1 int,f2 int);
+insert into t1 values(1,1);
+create table t2 (f3 int, f4 int, primary key(f3,f4));
+insert into t2 values(1,1);
+select * from t1 where f1 in (select f3 from t2 where (f3,f4)= (select f3,f4 from t2));
+f1	f2
+1	1
+drop table t1,t2;
diff --git a/mysql-test/t/select.test b/mysql-test/t/select.test
index 39c7cdfa8a..996d585485 100644
--- a/mysql-test/t/select.test
+++ b/mysql-test/t/select.test
@@ -2237,4 +2237,15 @@ insert into t1 values (1,1);
 insert into t2 values (1,1),(1,2);
 select distinct count(f2) >0 from t1 left join t2 on f1=f3 group by f1;
 drop table t1,t2;
+
+#
+# Bug #14482 Server crash when subselecting from the same table
+#
+create table t1 (f1 int,f2 int);
+insert into t1 values(1,1);
+create table t2 (f3 int, f4 int, primary key(f3,f4));
+insert into t2 values(1,1);
+select * from t1 where f1 in (select f3 from t2 where (f3,f4)= (select f3,f4 from t2)); 
+drop table t1,t2;
+
 # End of 4.1 tests
diff --git a/sql/item.cc b/sql/item.cc
index 642a0ccf1b..6ca2627dbf 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -2863,7 +2863,7 @@ Item_result item_cmp_type(Item_result a,Item_result b)
 void resolve_const_item(THD *thd, Item **ref, Item *comp_item)
 {
   Item *item= *ref;
-  Item *new_item;
+  Item *new_item= NULL;
   if (item->basic_const_item())
     return;                                     // Can't be better
   Item_result res_type=item_cmp_type(comp_item->result_type(),
@@ -2892,8 +2892,17 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item)
     new_item= (null_value ? (Item*) new Item_null(name) :
                (Item*) new Item_int(name, result, length));
   }
-  else if (res_type == ROW_RESULT)
+  else if (res_type == ROW_RESULT && item->type() == Item::ROW_ITEM &&
+           comp_item->type() == Item::ROW_ITEM)
   {
+    /*
+      Substitute constants only in Item_rows. Don't affect other Items
+      with ROW_RESULT (eg Item_singlerow_subselect).
+
+      For such Items more optimal is to detect if it is constant and replace
+      it with Item_row. This would optimize queries like this:
+      SELECT * FROM t1 WHERE (a,b) = (SELECT a,b FROM t2 LIMIT 1);
+    */
     Item_row *item_row= (Item_row*) item;
     Item_row *comp_item_row= (Item_row*) comp_item;
     uint col;
@@ -2910,7 +2919,7 @@ void resolve_const_item(THD *thd, Item **ref, Item *comp_item)
     while (col-- > 0)
       resolve_const_item(thd, item_row->addr(col), comp_item_row->el(col));
   }
-  else
+  else if (res_type == REAL_RESULT)
   {						// It must REAL_RESULT
     double result=item->val();
     uint length=item->max_length,decimals=item->decimals;
-- 
2.30.9