--- a/sql/item_cmpfunc.h	Thu Mar  8 17:29:58 2007
+++ b/sql/item_cmpfunc.h	Sun Apr  8 16:02:59 2007
@@ -472,65 +472,75 @@
 class Item_func_ge :public Item_bool_rowready_func2
 {
 public:
-  Item_func_ge(Item *a,Item *b) :Item_bool_rowready_func2(a,b) {};
+  Item_func_ge(Item *a,Item *b) :Item_bool_rowready_func2(a,b)
+    { abort_on_null= TRUE; };
   longlong val_int();
   enum Functype functype() const { return GE_FUNC; }
   enum Functype rev_functype() const { return LE_FUNC; }
   cond_result eq_cmp_result() const { return COND_TRUE; }
   const char *func_name() const { return ">="; }
   Item *negated_item();
+  void top_level_item() {}
 };
 
 
 class Item_func_gt :public Item_bool_rowready_func2
 {
 public:
-  Item_func_gt(Item *a,Item *b) :Item_bool_rowready_func2(a,b) {};
+  Item_func_gt(Item *a,Item *b) :Item_bool_rowready_func2(a,b)
+    { abort_on_null= TRUE; };
   longlong val_int();
   enum Functype functype() const { return GT_FUNC; }
   enum Functype rev_functype() const { return LT_FUNC; }
   cond_result eq_cmp_result() const { return COND_FALSE; }
   const char *func_name() const { return ">"; }
   Item *negated_item();
+  void top_level_item() {}
 };
 
 
 class Item_func_le :public Item_bool_rowready_func2
 {
 public:
-  Item_func_le(Item *a,Item *b) :Item_bool_rowready_func2(a,b) {};
+  Item_func_le(Item *a,Item *b) :Item_bool_rowready_func2(a,b)
+    { abort_on_null= TRUE; };
   longlong val_int();
   enum Functype functype() const { return LE_FUNC; }
   enum Functype rev_functype() const { return GE_FUNC; }
   cond_result eq_cmp_result() const { return COND_TRUE; }
   const char *func_name() const { return "<="; }
   Item *negated_item();
+  void top_level_item() {}
 };
 
 
 class Item_func_lt :public Item_bool_rowready_func2
 {
 public:
-  Item_func_lt(Item *a,Item *b) :Item_bool_rowready_func2(a,b) {}
+  Item_func_lt(Item *a,Item *b) :Item_bool_rowready_func2(a,b)
+    { abort_on_null= TRUE; };
   longlong val_int();
   enum Functype functype() const { return LT_FUNC; }
   enum Functype rev_functype() const { return GT_FUNC; }
   cond_result eq_cmp_result() const { return COND_FALSE; }
   const char *func_name() const { return "<"; }
   Item *negated_item();
+  void top_level_item() {}
 };
 
 
 class Item_func_ne :public Item_bool_rowready_func2
 {
 public:
-  Item_func_ne(Item *a,Item *b) :Item_bool_rowready_func2(a,b) {}
+  Item_func_ne(Item *a,Item *b) :Item_bool_rowready_func2(a,b)
+    { abort_on_null= FALSE; };
   longlong val_int();
   enum Functype functype() const { return NE_FUNC; }
   cond_result eq_cmp_result() const { return COND_FALSE; }
   optimize_type select_optimize() const { return OPTIMIZE_KEY; } 
   const char *func_name() const { return "<>"; }
   Item *negated_item();
+  void top_level_item() {}
 };
 
 
--- a/sql/item_cmpfunc.cc	Thu Mar 22 19:48:37 2007
+++ b/sql/item_cmpfunc.cc	Sun Apr  8 15:14:15 2007
@@ -744,10 +744,41 @@
   return (val1 >= 0) && test(val1 == val2);
 }
 
+/*
+  compare_row - compare 2 rows for eq, ne, gt, ge, ...
+
+  DESCRIPTION
+    compare_row and its optimization depend on the calling operation
+
+    EQ 
+      must compare all value pairs, even if a null result occured
+      (1,2) = (null, 2) returns NULL
+      (1,2) = (null, 3) returns FALSE
+
+    EQ with abort_on_null
+      can return NULL instead of FALSE.
+      compare can be aborted, on a null result
+
+    NE
+      (1,2) = (null, 2) returns NULL
+      (1,2) = (null, 3) returns TRUE
+    NE can not abort on abort_on_null, because it can be true
+
+    GT, GE, LT, LE
+      compare_row must return on the first differnece encountered.
+      This includes NULL results too.
+
+    This is archived by ensuring, that NE always has abort_on_null==0,
+    while GT, GE, LT, LE always have abort_on_null==1
+
+    <=> is handled in compare_e_row
+ */
 int Arg_comparator::compare_row()
 {
   int res= 0;
   bool was_null= 0;
+  bool abort_on_null= owner->abort_on_null;
+
   (*a)->bring_value();
   (*b)->bring_value();
   uint n= (*a)->cols();
@@ -757,7 +788,7 @@
     if (owner->null_value)
     {
       // NULL was compared
-      if (owner->abort_on_null)
+      if (abort_on_null)
         return -1; // We do not need correct NULL returning
       was_null= 1;
       owner->null_value= 0;
@@ -1036,6 +1067,7 @@
 {
   DBUG_ASSERT(fixed == 1);
   int value= cmp.compare();
+  // we don't need to test null_value, as it can only be true if result==-1
   return value >= 0 ? 1 : 0;
 }
 
