*** sql/item_func.cc	Mon Mar 19 20:59:20 2007
--- ../mysql-5.0.bk-sub-aggr/sql/item_func.cc	Tue Mar 27 20:25:34 2007
***************
*** 163,174 ****
--- 163,184 ----
  	return TRUE;				/* purecov: inspected */
        item= *arg;
  
        if (allowed_arg_cols)
        {
+ 	/*
+ 	  allowed_arg_cols could have been set by the function, rather than
+ 	  being fetched from the 1st column.
+ 	*/
          if (item->check_cols(allowed_arg_cols))
            return 1;
+ 	/*
+ 	  Don't compare the item with itself
+ 	  Currently all args to a function must have the same structure
+ 	*/
+         if (arg != args && item->check_cols_deeply(*args))
+           return 1;
        }
        else
        {
          /*  we have to fetch allowed_arg_cols from first argument */
          DBUG_ASSERT(arg == args); // it is first argument
*** sql/item.h	Thu Mar 22 08:21:02 2007
--- ../mysql-5.0.bk-sub-aggr/sql/item.h	Tue Mar 27 18:39:46 2007
***************
*** 811,820 ****
--- 811,824 ----
    // Row emulation
    virtual uint cols() { return 1; }
    virtual Item* element_index(uint i) { return this; }
    virtual Item** addr(uint i) { return 0; }
    virtual bool check_cols(uint c);
+ #ifndef DBUG_OFF
+   bool in_check_cols_deeply;
+ #endif
+   bool check_cols_deeply(Item* item);
    // It is not row => null inside is impossible
    virtual bool null_inside() { return 0; }
    // used in row subselects to get value of elements
    virtual void bring_value() {}
  
*** sql/item_cmpfunc.cc	Thu Mar 22 19:48:37 2007
--- ../mysql-5.0.bk-sub-aggr/sql/item_cmpfunc.cc	Tue Mar 27 21:05:22 2007
***************
*** 2548,2557 ****
--- 2548,2558 ----
  
  
  int cmp_item_row::cmp(Item *arg)
  {
    arg->null_value= 0;
+   DBUG_ASSERT(n == arg->cols());
    if (arg->cols() != n)
    {
      my_error(ER_OPERAND_COLUMNS, MYF(0), n);
      return 1;
    }
***************
*** 2571,2580 ****
--- 2572,2591 ----
  
  
  int cmp_item_row::compare(cmp_item *c)
  {
    cmp_item_row *l_cmp= (cmp_item_row *) c;
+   /*
+     This also asserts that c is a row, because rows have min 2 cols
+     if n >= 2 then c->cols >= 2
+   */
+   DBUG_ASSERT(n == c->cols());
+   if (c->cols() != n)
+   {
+     my_error(ER_OPERAND_COLUMNS, MYF(0), n);
+     return 1;
+   }
    for (uint i=0; i < n; i++)
    {
      int res;
      if ((res= comparators[i]->compare(l_cmp->comparators[i])))
        return res;
***************
*** 2766,2775 ****
--- 2777,2789 ----
  	if (!args[i]->null_value)			// Skip NULL values
  	  j++;
  	else
  	  have_null= 1;
        }
+       /* If an error inside array->set occured, array->sort could fail */
+       if (thd->net.report_error)
+         return;
        if ((array->used_count=j))
  	array->sort();
      }
    }
    else
*** sql/item_cmpfunc.h	Thu Mar  8 17:29:58 2007
--- ../mysql-5.0.bk-sub-aggr/sql/item_cmpfunc.h	Tue Mar 27 18:05:39 2007
***************
*** 905,916 ****
--- 905,926 ----
    virtual int cmp(Item *item)= 0;
    // for optimized IN with row
    virtual int compare(cmp_item *item)= 0;
    static cmp_item* get_comparator(Item_result type, CHARSET_INFO *cs);
    virtual cmp_item *make_same()= 0;
+   virtual uint cols()
+   {
+     return 1;
+   }
    virtual void store_value_by_template(cmp_item *tmpl, Item *item)
    {
+     DBUG_ASSERT(tmpl->cols() == item->cols());
+     if (tmpl->cols() != item->cols())
+     {
+       my_error(ER_OPERAND_COLUMNS, MYF(0), tmpl->cols());
+       return;
+     }
      store_value(item);
    }
  };
  
  class cmp_item_string :public cmp_item 
***************
*** 1016,1025 ****
--- 1026,1039 ----
    ~cmp_item_row();
    void store_value(Item *item);
    int cmp(Item *arg);
    int compare(cmp_item *arg);
    cmp_item *make_same();
+   uint cols()
+   {
+     return n;
+   }
    void store_value_by_template(cmp_item *tmpl, Item *);
  };
  
  
  class in_row :public in_vector
*** sql/item.cc	Thu Mar 22 12:37:24 2007
--- ../mysql-5.0.bk-sub-aggr/sql/item.cc	Tue Mar 27 19:06:41 2007
***************
*** 339,348 ****
--- 339,351 ----
  Item::Item():
    rsize(0), name(0), orig_name(0), name_length(0), fixed(0),
    is_autogenerated_name(TRUE),
    collation(&my_charset_bin, DERIVATION_COERCIBLE)
  {
+ #ifndef DBUG_OFF
+   in_check_cols_deeply= 0;
+ #endif
    marker= 0;
    maybe_null=null_value=with_sum_func=unsigned_flag=0;
    decimals= 0; max_length= 0;
    with_subselect= 0;
    cmp_context= (Item_result)-1;
***************
*** 385,394 ****
--- 388,400 ----
    with_sum_func(item->with_sum_func),
    fixed(item->fixed),
    collation(item->collation),
    cmp_context(item->cmp_context)
  {
+ #ifndef DBUG_OFF
+   in_check_cols_deeply= 0;
+ #endif
    next= thd->free_list;				// Put in free list
    thd->free_list= this;
  }
  
  
***************
*** 644,653 ****
--- 650,686 ----
      return 1;
    }
    return 0;
  }
  
+ bool Item::check_cols_deeply(Item* item)
+ {
+ #ifndef DBUG_OFF
+   DBUG_ASSERT(! in_check_cols_deeply);
+   in_check_cols_deeply= 1;
+ #endif
+   if(cols() != item->cols())
+   {
+     my_error(ER_OPERAND_COLUMNS, MYF(0), item->cols());
+     return 1;
+   }
+   for (int c= 0; c < cols(); c++)
+   {
+     Item* i= element_index(c);
+     if (i != this && i->check_cols_deeply(item->element_index(c)))
+     {
+ #ifndef DBUG_OFF
+       in_check_cols_deeply= 0;
+ #endif
+       return 1;
+     }
+   }
+ #ifndef DBUG_OFF
+   in_check_cols_deeply= 0;
+ #endif
+   return 0;
+ }
  
  void Item::set_name(const char *str, uint length, CHARSET_INFO *cs)
  {
    if (!length)
    {
*** mysql-test/t/row.test	Tue Mar 27 18:16:34 2007
--- ../mysql-5.0.bk-sub-aggr/mysql-test/t/row.test	Tue Mar 27 20:45:42 2007
***************
*** 139,141 ****
--- 139,184 ----
  SELECT * FROM t1,t2 WHERE t2.a=t1.a AND (t2.b,t2.c)=(2,1);
  
  DROP TABLE t1,t2;
+ 
+ #
+ # BUG #27484
+ # row() in "IN()"
+ #
+ 
+ #nested row() in "IN()" could cause a crash,
+ #if a row was compared to a different type or a row of differnet length
+ 
+ # qsort / compare
+ -- error 1241
+ select row(1,row(2,3))   IN (row(1,row(2,3))   ,row(1,1));
+ -- error 1241
+ select row(1,row(2,3))   IN (row(1,row(2,3))   ,row(1,1), row(1,row(2,3)));
+ -- error 1241
+ select row(1,row(2,3))   IN (row(1,row(2,3))   ,row(1,row(2,2,2)));
+ -- error 1241
+ select row(1,row(2,3,4)) IN (row(1,row(2,3,4)) ,row(1,row(2,2)));
+ 
+ # the following were not affected, but should be tested
+ -- error 1241
+ select row(1,row(2,3))   IN (row(1,1),          row(1,row(2,3)));
+ -- error 1241
+ select row(1,row(2,3))   IN (row(1,row(2,2,2)), row(1,row(2,3)));
+ -- error 1241
+ select row(1,row(2,3,4)) IN (row(1,row(2,2)),   row(1,row(2,3,4)));
+ 
+ 
+ #using subselect in nested row() and IN(), invalid statements were accepted with no error
+ --error 1241
+ select row(1,row(2,3)) IN (row(1,row(2,3)), (select 1,1));
+ --error 1241
+ select row(1,row(2,3)) IN (row(1,row(2,3)), (select 1,1), row(1,row(2,4)));
+ --error 1241
+ select row(1,row(2,3)) IN ((select 1,1), row(1,row(2,3)));
+ 
+ #debug asserts happened with nested row() / run the below with a debug server
+ 
+ -- error 1241
+ select row(2,1) IN (row(21,2), row(row(1,1,3),0) );
+ -- error 1241
+ select row(2,1) IN (row(row(1,1,3),0), row(21,2));
+ 
*** mysql-test/r/row.result	Tue Mar 27 18:16:33 2007
--- ../mysql-5.0.bk-sub-aggr/mysql-test/r/row.result	Tue Mar 27 20:46:54 2007
***************
*** 306,308 ****
--- 306,332 ----
  1	1	1	2	1
  1	2	1	2	1
  DROP TABLE t1,t2;
+ select row(1,row(2,3))   IN (row(1,row(2,3))   ,row(1,1));
+ ERROR 21000: Operand should contain 2 column(s)
+ select row(1,row(2,3))   IN (row(1,row(2,3))   ,row(1,1), row(1,row(2,3)));
+ ERROR 21000: Operand should contain 2 column(s)
+ select row(1,row(2,3))   IN (row(1,row(2,3))   ,row(1,row(2,2,2)));
+ ERROR 21000: Operand should contain 2 column(s)
+ select row(1,row(2,3,4)) IN (row(1,row(2,3,4)) ,row(1,row(2,2)));
+ ERROR 21000: Operand should contain 3 column(s)
+ select row(1,row(2,3))   IN (row(1,1),          row(1,row(2,3)));
+ ERROR 21000: Operand should contain 2 column(s)
+ select row(1,row(2,3))   IN (row(1,row(2,2,2)), row(1,row(2,3)));
+ ERROR 21000: Operand should contain 2 column(s)
+ select row(1,row(2,3,4)) IN (row(1,row(2,2)),   row(1,row(2,3,4)));
+ ERROR 21000: Operand should contain 3 column(s)
+ select row(1,row(2,3)) IN (row(1,row(2,3)), (select 1,1));
+ ERROR 21000: Operand should contain 2 column(s)
+ select row(1,row(2,3)) IN (row(1,row(2,3)), (select 1,1), row(1,row(2,4)));
+ ERROR 21000: Operand should contain 2 column(s)
+ select row(1,row(2,3)) IN ((select 1,1), row(1,row(2,3)));
+ ERROR 21000: Operand should contain 2 column(s)
+ select row(2,1) IN (row(21,2), row(row(1,1,3),0) );
+ ERROR 21000: Operand should contain 1 column(s)
+ select row(2,1) IN (row(row(1,1,3),0), row(21,2));
+ ERROR 21000: Operand should contain 1 column(s)
