From 8f2f1597500c4cf74d5d73a4ee04b54f440df695 Mon Sep 17 00:00:00 2001
From: unknown <monty@hundin.mysql.fi>
Date: Fri, 22 Mar 2002 14:03:42 +0200
Subject: [PATCH] Fix for bug in WHERE key='j' or key='J'

Docs/manual.texi:
  Changelog
myisam/myisampack.c:
  Delete tmp file on error.
mysql-test/r/range.result:
  Updated test case
mysql-test/t/range.test:
  Updated test case
---
 Docs/manual.texi          |  4 +++-
 myisam/myisampack.c       | 17 +++++------------
 mysql-test/r/range.result | 10 ++++++++++
 mysql-test/t/range.test   |  3 ++-
 sql/item.cc               | 23 ++++++++++++++++++++---
 sql/item.h                | 10 ++++++----
 sql/item_func.cc          | 10 +++++-----
 sql/item_func.h           |  6 +++---
 sql/sql_base.cc           |  6 +++---
 sql/sql_select.cc         | 28 ++++++++++++++--------------
 10 files changed, 71 insertions(+), 46 deletions(-)

diff --git a/Docs/manual.texi b/Docs/manual.texi
index b33da6a91d5..600ad5efe5a 100644
--- a/Docs/manual.texi
+++ b/Docs/manual.texi
@@ -46897,6 +46897,8 @@ not yet 100% confident in this code.
 @appendixsubsec Changes in release 3.23.50
 @itemize @bullet
 @item
+Fixed bug when using @code{WHERE key_column = 'J' or key_column='j'}.
+@item
 Fixed core-dump bug when using @code{--log-bin} with @code{LOAD DATA
 INFILE} without an active database.
 @item
@@ -46934,7 +46936,7 @@ Don't give warning for statement that is only a comment;  This is needed for
 @code{mysqldump --disable-keys} to work.
 @item
 Fixed unlikely caching bug when doing a join without keys. In this case
-the last used field for a table always returned @code{NULL}.
+the last used column for a table always returned @code{NULL}.
 @item
 Added options to make @code{LOAD DATA LOCAL INFILE} more secure.
 @item
diff --git a/myisam/myisampack.c b/myisam/myisampack.c
index 98fa8fcb377..81ae77738ea 100644
--- a/myisam/myisampack.c
+++ b/myisam/myisampack.c
@@ -251,7 +251,7 @@ static struct option long_options[] =
 
 static void print_version(void)
 {
-  printf("%s  Ver 1.11 for %s on %s\n",my_progname,SYSTEM_TYPE,MACHINE_TYPE);
+  printf("%s  Ver 1.12 for %s on %s\n",my_progname,SYSTEM_TYPE,MACHINE_TYPE);
 }
 
 static void usage(void)
@@ -594,10 +594,7 @@ static int compress(PACK_MRG_INFO *mrg,char *result_table)
 	else
 	{
 	  if (tmp_dir[0])
-	  {
-	    if (!(error=my_copy(new_name,org_name,MYF(MY_WME))))
-	      VOID(my_delete(new_name,MYF(MY_WME)));
-	  }
+	    error=my_copy(new_name,org_name,MYF(MY_WME));
 	  else
 	    error=my_rename(new_name,org_name,MYF(MY_WME));
 	  if (!error)
@@ -607,13 +604,8 @@ static int compress(PACK_MRG_INFO *mrg,char *result_table)
       else
       {
 	if (tmp_dir[0])
-	{
-
-	  if (!(error=my_copy(new_name,org_name,
-			      MYF(MY_WME | MY_HOLD_ORIGINAL_MODES
-				  | MY_COPYTIME))))
-	    VOID(my_delete(new_name,MYF(MY_WME)));
-	}
+	  error=my_copy(new_name,org_name,
+			MYF(MY_WME | MY_HOLD_ORIGINAL_MODES | MY_COPYTIME));
 	else
 	  error=my_redel(org_name,new_name,MYF(MY_WME | MY_COPYTIME));
       }
@@ -627,6 +619,7 @@ static int compress(PACK_MRG_INFO *mrg,char *result_table)
   if (error)
   {
     VOID(fprintf(stderr,"Aborting: %s is not compressed\n",org_name));
+    VOID(my_delete(new_name,MYF(MY_WME)));
     DBUG_RETURN(-1);
   }
   if (write_loop || verbose)
diff --git a/mysql-test/r/range.result b/mysql-test/r/range.result
index e0e43f44a4b..1a45c252b7c 100644
--- a/mysql-test/r/range.result
+++ b/mysql-test/r/range.result
@@ -55,3 +55,13 @@ believe
 believe in love
 aString
 believe in myself
+count(*)
+602
+count(*)
+602
+count(*)
+602
+count(*)
+389
+count(*)
+213
diff --git a/mysql-test/t/range.test b/mysql-test/t/range.test
index ccb66506efd..278807eeea4 100644
--- a/mysql-test/t/range.test
+++ b/mysql-test/t/range.test
@@ -105,7 +105,6 @@ drop table t1;
 # Problem with binary strings
 #
 
-DROP TABLE IF EXISTS t1;
 CREATE TABLE t1 (
   t1ID int(10) unsigned NOT NULL auto_increment,
   art char(1) binary NOT NULL default '',
@@ -161,4 +160,6 @@ INSERT INTO t1 (art) VALUES ('j'),('J'),('j'),('J'),('j'),('J'),('j'),('J'),('j'
 select count(*) from t1 where upper(art) = 'J';
 select count(*) from t1 where art = 'J' or art = 'j';
 select count(*) from t1 where art = 'j' or art = 'J';
+select count(*) from t1 where art = 'j';
+select count(*) from t1 where art = 'J';
 drop table t1;
diff --git a/sql/item.cc b/sql/item.cc
index b268c5eb928..0ce37cdd593 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -59,12 +59,28 @@ void Item::set_name(char *str,uint length)
   }
 }
 
-bool Item::eq(const Item *item) const		// Only doing this on conds
+/*
+  This function is only called when comparing items in the WHERE clause
+*/
+
+bool Item::eq(const Item *item, bool binary_cmp) const
 {
   return type() == item->type() && name && item->name &&
     !my_strcasecmp(name,item->name);
 }
 
+bool Item_string::eq(const Item *item, bool binary_cmp) const
+{
+  if (type() == item->type())
+  {
+    if (binary_cmp)
+      return !stringcmp(&str_value, &item->str_value);
+    return !sortcmp(&str_value, &item->str_value);
+  }
+  return 0;
+}
+
+
 /*
   Get the value of the function as a TIME structure.
   As a extra convenience the time structure is reset on error!
@@ -202,7 +218,7 @@ longlong Item_field::val_int_result()
   return result_field->val_int();
 }
 
-bool Item_field::eq(const Item *item) const
+bool Item_field::eq(const Item *item, bool binary_cmp) const
 {
   return item->type() == FIELD_ITEM && ((Item_field*) item)->field == field;
 }
@@ -245,7 +261,8 @@ void Item_string::print(String *str)
   str->append('\'');
 }
 
-bool Item_null::eq(const Item *item) const { return item->type() == type(); }
+bool Item_null::eq(const Item *item, bool binary_cmp) const
+{ return item->type() == type(); }
 double Item_null::val() { null_value=1; return 0.0; }
 longlong Item_null::val_int() { null_value=1; return 0; }
 /* ARGSUSED */
diff --git a/sql/item.h b/sql/item.h
index c868f9d3bf7..41b897956db 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -56,7 +56,7 @@ class Item {
   virtual void save_org_in_field(Field *field)
     { (void) save_in_field(field); }
   virtual bool send(String *str);
-  virtual bool eq(const Item *) const;
+  virtual bool eq(const Item *, bool binary_cmp) const;
   virtual Item_result result_type () const { return REAL_RESULT; }
   virtual enum Type type() const =0;
   virtual double val()=0;
@@ -109,7 +109,7 @@ class Item_field :public Item_ident
   {}
   Item_field(Field *field);
   enum Type type() const { return FIELD_ITEM; }
-  bool eq(const Item *item) const;
+  bool eq(const Item *item, bool binary_cmp) const;
   double val();
   longlong val_int();
   String *val_str(String*);
@@ -138,7 +138,7 @@ class Item_null :public Item
   Item_null(char *name_par=0)
     { maybe_null=null_value=TRUE; name= name_par ? name_par : (char*) "NULL";}
   enum Type type() const { return NULL_ITEM; }
-  bool eq(const Item *item) const;
+  bool eq(const Item *item, bool binary_cmp) const;
   double val();
   longlong val_int();
   String *val_str(String *str);
@@ -247,6 +247,7 @@ class Item_string :public Item
   void make_field(Send_field *field);
   enum Item_result result_type () const { return STRING_RESULT; }
   bool basic_const_item() const { return 1; }
+  bool eq(const Item *item, bool binary_cmp) const;
   Item *new_item() { return new Item_string(name,str_value.ptr(),max_length); }
   String *const_string() { return &str_value; }
   inline void append(char *str,uint length) { str_value.append(str,length); }
@@ -306,7 +307,8 @@ class Item_ref :public Item_ident
   Item_ref(Item **item, char *table_name_par,char *field_name_par)
     :Item_ident(NullS,table_name_par,field_name_par),ref(item) {}
   enum Type type() const		{ return REF_ITEM; }
-  bool eq(const Item *item) const	{ return (*ref)->eq(item); }
+  bool eq(const Item *item, bool binary_cmp) const
+  { return (*ref)->eq(item, binary_cmp); }
   ~Item_ref() { if (ref) delete *ref; }
   double val()
   {
diff --git a/sql/item_func.cc b/sql/item_func.cc
index e7e8964b07a..9f94a25cbf9 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -148,7 +148,7 @@ void Item_func::print_op(String *str)
   str->append(')');
 }
 
-bool Item_func::eq(const Item *item) const
+bool Item_func::eq(const Item *item, bool binary_cmp) const
 {
   /* Assume we don't have rtti */
   if (this == item)
@@ -160,7 +160,7 @@ bool Item_func::eq(const Item *item) const
       func_name() != item_func->func_name())
     return 0;
   for (uint i=0; i < arg_count ; i++)
-    if (!args[i]->eq(item_func->args[i]))
+    if (!args[i]->eq(item_func->args[i], binary_cmp))
       return 0;
   return 1;
 }
@@ -1882,7 +1882,7 @@ void Item_func_get_user_var::print(String *str)
   str->append(')');
 }
 
-bool Item_func_get_user_var::eq(const Item *item) const
+bool Item_func_get_user_var::eq(const Item *item, bool binary_cmp) const
 {
   /* Assume we don't have rtti */
   if (this == item)
@@ -2135,7 +2135,7 @@ bool Item_func_match::fix_index()
   return 1;
 }
 
-bool Item_func_match::eq(const Item *item) const
+bool Item_func_match::eq(const Item *item, bool binary_cmp) const
 {
   if (item->type() != FUNC_ITEM)
     return 0;
@@ -2146,7 +2146,7 @@ bool Item_func_match::eq(const Item *item) const
   Item_func_match *ifm=(Item_func_match*) item;
 
   if (key == ifm->key && table == ifm->table &&
-      key_item()->eq(ifm->key_item()))
+      key_item()->eq(ifm->key_item(), binary_cmp))
     return 1;
 
   return 0;
diff --git a/sql/item_func.h b/sql/item_func.h
index 4a8f808de57..35af4540f7c 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -98,7 +98,7 @@ class Item_func :public Item_result_field
   void make_field(Send_field *field);
   table_map used_tables() const;
   void update_used_tables();
-  bool eq(const Item *item) const;
+  bool eq(const Item *item, bool binary_cmp) const;
   virtual optimize_type select_optimize() const { return OPTIMIZE_NONE; }
   virtual bool have_rev_func() const { return 0; }
   virtual Item *key_item() const { return args[0]; }
@@ -842,7 +842,7 @@ class Item_func_get_user_var :public Item_func
   bool const_item() const { return const_var_flag; }
   table_map used_tables() const
   { return const_var_flag ? 0 : RAND_TABLE_BIT; }
-  bool eq(const Item *item) const;
+  bool eq(const Item *item, bool binary_cmp) const;
 };
 
 
@@ -887,7 +887,7 @@ class Item_func_match :public Item_real_func
   enum Functype functype() const { return FT_FUNC; }
   void update_used_tables() {}
   bool fix_fields(THD *thd,struct st_table_list *tlist);
-  bool eq(const Item *) const;
+  bool eq(const Item *, bool binary_cmp) const;
   double val();
   longlong val_int() { return val()!=0.0; }
 
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 985118ee218..e4a797efaaf 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -1718,7 +1718,7 @@ find_item_in_list(Item *find,List<Item> &items)
 	{
 	  if (found)
 	  {
-	    if ((*found)->eq(item))
+	    if ((*found)->eq(item,0))
 	      continue;				// Same field twice (Access?)
 	    if (current_thd->where)
 	      my_printf_error(ER_NON_UNIQ_ERROR,ER(ER_NON_UNIQ_ERROR),MYF(0),
@@ -1734,7 +1734,7 @@ find_item_in_list(Item *find,List<Item> &items)
 	}
       }
     }
-    else if (!table_name && (item->eq(find) ||
+    else if (!table_name && (item->eq(find,0) ||
 			     find->name &&
 			     !my_strcasecmp(item->name,find->name)))
     {
@@ -2213,7 +2213,7 @@ int setup_ftfuncs(THD *thd)
     lj.rewind();
     while ((ftf2=lj++) != ftf)
     {
-      if (ftf->eq(ftf2) && !ftf2->master)
+      if (ftf->eq(ftf2,1) && !ftf2->master)
         ftf2->master=ftf;
     }
   }
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 1ee0d84e182..b7134062437 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -1100,14 +1100,14 @@ merge_key_fields(KEY_FIELD *start,KEY_FIELD *new_fields,KEY_FIELD *end,
       {
 	if (new_fields->val->used_tables())
 	{
-	  if (old->val->eq(new_fields->val))
+	  if (old->val->eq(new_fields->val, old->field->binary()))
 	  {
 	    old->level=old->const_level=and_level;
 	    old->exists_optimize&=new_fields->exists_optimize;
 	  }
 	}
-	else if (old->val->eq(new_fields->val) && old->eq_func &&
-		 new_fields->eq_func)
+	else if (old->val->eq(new_fields->val, old->field->binary()) &&
+		 old->eq_func && new_fields->eq_func)
 	{
 	  old->level=old->const_level=and_level;
 	  old->exists_optimize&=new_fields->exists_optimize;
@@ -2602,7 +2602,7 @@ eq_ref_table(JOIN *join, ORDER *start_order, JOIN_TAB *tab)
       ORDER *order;
       for (order=start_order ; order ; order=order->next)
       {
-	if ((*ref_item)->eq(order->item[0]))
+	if ((*ref_item)->eq(order->item[0],0))
 	  break;
       }
       if (order)
@@ -2859,7 +2859,7 @@ change_cond_ref_to_const(I_List<COND_CMP> *save_list,Item *and_father,
   Item *right_item= func->arguments()[1];
   Item_func::Functype functype=  func->functype();
 
-  if (right_item->eq(field) && left_item != value)
+  if (right_item->eq(field,0) && left_item != value)
   {
     Item *tmp=value->new_item();
     if (tmp)
@@ -2878,7 +2878,7 @@ change_cond_ref_to_const(I_List<COND_CMP> *save_list,Item *and_father,
 				       func->arguments()[1]->result_type()));
     }
   }
-  else if (left_item->eq(field) && right_item != value)
+  else if (left_item->eq(field,0) && right_item != value)
   {
     Item *tmp=value->new_item();
     if (tmp)
@@ -3118,7 +3118,7 @@ remove_eq_conds(COND *cond,Item::cond_result *cond_value)
   {						// boolan compare function
     Item *left_item=	((Item_func*) cond)->arguments()[0];
     Item *right_item= ((Item_func*) cond)->arguments()[1];
-    if (left_item->eq(right_item))
+    if (left_item->eq(right_item,1))
     {
       if (!left_item->maybe_null ||
 	  ((Item_func*) cond)->functype() == Item_func::EQUAL_FUNC)
@@ -3163,22 +3163,22 @@ const_expression_in_where(COND *cond, Item *comp_item, Item **const_item)
       return 0;
     Item *left_item=	((Item_func*) cond)->arguments()[0];
     Item *right_item= ((Item_func*) cond)->arguments()[1];
-    if (left_item->eq(comp_item))
+    if (left_item->eq(comp_item,1))
     {
       if (right_item->const_item())
       {
 	if (*const_item)
-	  return right_item->eq(*const_item);
+	  return right_item->eq(*const_item, 1);
 	*const_item=right_item;
 	return 1;
       }
     }
-    else if (right_item->eq(comp_item))
+    else if (right_item->eq(comp_item,1))
     {
       if (left_item->const_item())
       {
 	if (*const_item)
-	  return left_item->eq(*const_item);
+	  return left_item->eq(*const_item, 1);
 	*const_item=left_item;
 	return 1;
       }
@@ -4970,7 +4970,7 @@ static bool test_if_ref(Item_field *left_item,Item *right_item)
   if (!field->table->const_table && !field->table->maybe_null)
   {
     Item *ref_item=part_of_refkey(field->table,field);
-    if (ref_item && ref_item->eq(right_item))
+    if (ref_item && ref_item->eq(right_item,1))
     {
       if (right_item->type() == Item::FIELD_ITEM)
 	return (field->eq_def(((Item_field *) right_item)->field));
@@ -6151,7 +6151,7 @@ test_if_subpart(ORDER *a,ORDER *b)
 {
   for (; a && b; a=a->next,b=b->next)
   {
-    if ((*a->item)->eq(*b->item))
+    if ((*a->item)->eq(*b->item,1))
       a->asc=b->asc;
     else
       return 0;
@@ -6178,7 +6178,7 @@ get_sort_by_table(ORDER *a,ORDER *b,TABLE_LIST *tables)
 
   for (; a && b; a=a->next,b=b->next)
   {
-    if (!(*a->item)->eq(*b->item))
+    if (!(*a->item)->eq(*b->item,1))
       DBUG_RETURN(0);
     map|=a->item[0]->used_tables();
   }
-- 
2.30.9