List:Commits« Previous MessageNext Message »
From:Georgi Kodinov Date:October 17 2008 10:55am
Subject:bzr commit into mysql-5.0-bugteam branch (kgeorge:2707) Bug#38637
View as plain text  
#At file:///home/kgeorge/mysql/bzr/B38637-5.0-bugteam/

 2707 Georgi Kodinov	2008-10-17
      Bug #38637: COUNT DISTINCT prevents NULL testing in HAVING clause
      
      IS NULL was not checking the correct row in a HAVING context.
      At the first row of a new group (where the HAVING clause is evaluated)
      the column and SELECT list references in the HAVING clause should 
      refer to the last row of the previous group and not to the current one. 
      This was not done for IS NULL, because it was using Item::is_null() doesn't
      have a  Item_is_null_result() counterpart to access the data from the 
      last row of the previous group. Note that all the Item::val_xxx() functions 
      (e.g. Item::val_int()) have their _result counterparts (e.g. Item::val_int_result()).
      
      Fixed by implementing a is_null_result() (similarly to int_result()) and
      calling this instead of is_null() column and SELECT list references inside
      the HAVING clause.
modified:
  mysql-test/r/having.result
  mysql-test/t/having.test
  sql/item.cc
  sql/item.h
  sql/item_func.cc
  sql/item_func.h

per-file messages:
  mysql-test/r/having.result
    Bug #38637: test case
  mysql-test/t/having.test
    Bug #38637: test case
  sql/item.cc
    Bug #38637: implement Item::is_null_result() and call it
    from Item_ref and Item_field as appropriate.
  sql/item.h
    Bug #38637: implement Item::is_null_result() and call it
    from Item_ref and Item_field as appropriate.
  sql/item_func.cc
    Bug #38637: implement Item::is_null_result() and call it
    from Item_ref and Item_field as appropriate.
  sql/item_func.h
    Bug #38637: implement Item::is_null_result() and call it
    from Item_ref and Item_field as appropriate.
=== modified file 'mysql-test/r/having.result'
--- a/mysql-test/r/having.result	2007-07-21 19:34:18 +0000
+++ b/mysql-test/r/having.result	2008-10-17 10:55:16 +0000
@@ -424,3 +424,10 @@ select f1 from t1 group by f1 having max
 f1
 set session sql_mode='';
 drop table t1;
+CREATE TABLE t1 ( a INT, b INT);
+INSERT INTO t1 VALUES (1, 1), (2,2), (3, NULL);
+SELECT b, COUNT(DISTINCT a) FROM t1 GROUP BY b HAVING b is NULL;
+b	COUNT(DISTINCT a)
+NULL	1
+DROP TABLE t1;
+End of 5.0 tests

=== modified file 'mysql-test/t/having.test'
--- a/mysql-test/t/having.test	2007-07-21 19:34:18 +0000
+++ b/mysql-test/t/having.test	2008-10-17 10:55:16 +0000
@@ -432,3 +432,14 @@ select f1 from t1 having max(f1)=f1;
 select f1 from t1 group by f1 having max(f1)=f1;
 set session sql_mode='';
 drop table t1;
+
+
+#
+# Bug #38637: COUNT DISTINCT prevents NULL testing in HAVING clause
+#
+CREATE TABLE t1 ( a INT, b INT);
+INSERT INTO t1 VALUES (1, 1), (2,2), (3, NULL);
+SELECT b, COUNT(DISTINCT a) FROM t1 GROUP BY b HAVING b is NULL;
+DROP TABLE t1;
+
+--echo End of 5.0 tests

=== modified file 'sql/item.cc'
--- a/sql/item.cc	2008-10-14 14:04:36 +0000
+++ b/sql/item.cc	2008-10-17 10:55:16 +0000
@@ -2041,6 +2041,12 @@ bool Item_field::val_bool_result()
 }
 
 
+bool Item_field::is_null_result()
+{
+  return (null_value=result_field->is_null());
+}
+
+
 bool Item_field::eq(const Item *item, bool binary_cmp) const
 {
   Item *real_item= ((Item *) item)->real_item();
@@ -5626,6 +5632,15 @@ double Item_ref::val_result()
 }
 
 
+bool Item_ref::is_null_result()
+{
+  if (result_field)
+    return (null_value=result_field->is_null());
+
+  return is_null();
+}
+
+
 longlong Item_ref::val_int_result()
 {
   if (result_field)
@@ -5731,7 +5746,9 @@ String *Item_ref::val_str(String* tmp)
 bool Item_ref::is_null()
 {
   DBUG_ASSERT(fixed);
-  return (*ref)->is_null();
+  bool tmp=(*ref)->is_null_result();
+  null_value=(*ref)->null_value;
+  return tmp;
 }
 
 

=== modified file 'sql/item.h'
--- a/sql/item.h	2008-08-15 20:13:27 +0000
+++ b/sql/item.h	2008-10-17 10:55:16 +0000
@@ -652,6 +652,7 @@ public:
   virtual my_decimal *val_decimal_result(my_decimal *val)
   { return val_decimal(val); }
   virtual bool val_bool_result() { return val_bool(); }
+  virtual bool is_null_result() { return is_null(); }
 
   /* bit map of tables used by item */
   virtual table_map used_tables() const { return (table_map) 0L; }
@@ -1301,6 +1302,7 @@ public:
   String *str_result(String* tmp);
   my_decimal *val_decimal_result(my_decimal *);
   bool val_bool_result();
+  bool is_null_result();
   bool send(Protocol *protocol, String *str_arg);
   void reset_field(Field *f);
   bool fix_fields(THD *, Item **);
@@ -1942,6 +1944,7 @@ public:
   String *str_result(String* tmp);
   my_decimal *val_decimal_result(my_decimal *);
   bool val_bool_result();
+  bool is_null_result();
   bool send(Protocol *prot, String *tmp);
   void make_field(Send_field *field);
   bool fix_fields(THD *, Item **);

=== modified file 'sql/item_func.cc'
--- a/sql/item_func.cc	2008-07-30 11:07:37 +0000
+++ b/sql/item_func.cc	2008-10-17 10:55:16 +0000
@@ -4283,6 +4283,15 @@ my_decimal *Item_func_set_user_var::val_
 }
 
 
+bool Item_func_set_user_var::is_null_result()
+{
+  DBUG_ASSERT(fixed == 1);
+  check(TRUE);
+  update();					// Store expression
+  return is_null();
+}
+
+
 void Item_func_set_user_var::print(String *str)
 {
   str->append(STRING_WITH_LEN("(@"));

=== modified file 'sql/item_func.h'
--- a/sql/item_func.h	2008-02-28 13:23:22 +0000
+++ b/sql/item_func.h	2008-10-17 10:55:16 +0000
@@ -1299,6 +1299,7 @@ public:
   longlong val_int_result();
   String *str_result(String *str);
   my_decimal *val_decimal_result(my_decimal *);
+  bool is_null_result();
   bool update_hash(void *ptr, uint length, enum Item_result type,
   		   CHARSET_INFO *cs, Derivation dv, bool unsigned_arg);
   bool send(Protocol *protocol, String *str_arg);

Thread
bzr commit into mysql-5.0-bugteam branch (kgeorge:2707) Bug#38637Georgi Kodinov17 Oct