List:Commits« Previous MessageNext Message »
From:bar Date:August 16 2006 6:31am
Subject:bk commit into 4.1 tree (bar:1.2534)
View as plain text  
Below is the list of changes that have just been committed into a local
4.1 repository of bar. When bar does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet@stripped, 2006-08-16 09:31:24+05:00, bar@stripped +3 -0
  Merge mysql.com:/usr/home/bar/mysql-4.1
  into  mysql.com:/usr/home/bar/mysql-4.1.b9509
  MERGE: 1.2458.10.1

  mysql-test/r/ctype_utf8.result@stripped, 2006-08-16 09:31:19+05:00, bar@stripped +0 -0
    Auto merged
    MERGE: 1.69.1.5

  mysql-test/t/ctype_utf8.test@stripped, 2006-08-16 09:31:19+05:00, bar@stripped +0 -0
    Auto merged
    MERGE: 1.71.1.5

  sql/sql_select.cc@stripped, 2006-08-16 09:31:19+05:00, bar@stripped +0 -0
    Auto merged
    MERGE: 1.451.1.13

# This is a BitKeeper patch.  What follows are the unified diffs for the
# set of deltas contained in the patch.  The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User:	bar
# Host:	bar.intranet.mysql.r18.ru
# Root:	/usr/home/bar/mysql-4.1.b9509/RESYNC

--- 1.452/sql/sql_select.cc	2006-08-16 09:31:29 +05:00
+++ 1.453/sql/sql_select.cc	2006-08-16 09:31:29 +05:00
@@ -114,6 +114,10 @@
 static uint find_shortest_key(TABLE *table, const key_map *usable_keys);
 static bool test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,
 				    ha_rows select_limit, bool no_changes);
+static bool list_contains_unique_index(TABLE *table,
+                          bool (*find_func) (Field *, void *), void *data);
+static bool find_field_in_item_list (Field *field, void *data);
+static bool find_field_in_order_list (Field *field, void *data);
 static int create_sort_index(THD *thd, JOIN *join, ORDER *order,
 			     ha_rows filesort_limit, ha_rows select_limit);
 static int remove_duplicates(JOIN *join,TABLE *entry,List<Item> &fields,
@@ -171,7 +175,7 @@
   register SELECT_LEX *select_lex = &lex->select_lex;
   DBUG_ENTER("handle_select");
 
-  if (select_lex->next_select())
+  if (select_lex->next_select() || select_lex->master_unit()->fake_select_lex)
     res=mysql_union(thd, lex, result, &lex->unit);
   else
     res= mysql_select(thd, &select_lex->ref_pointer_array,
@@ -501,12 +505,24 @@
     DBUG_RETURN(1);
   }
 
-  if (cond_value == Item::COND_FALSE ||
-      (!unit->select_limit_cnt && !(select_options & OPTION_FOUND_ROWS)))
-  {						/* Impossible cond */
-    zero_result_cause= "Impossible WHERE";
-    error= 0;
-    DBUG_RETURN(0);
+  {
+    Item::cond_result having_value;
+    having= optimize_cond(thd, having, &having_value);
+    if (thd->net.report_error)
+    {
+      error= 1;
+      DBUG_PRINT("error",("Error from optimize_cond"));
+      DBUG_RETURN(1);
+    }
+
+    if (cond_value == Item::COND_FALSE || having_value == Item::COND_FALSE || 
+       (!unit->select_limit_cnt && !(select_options & OPTION_FOUND_ROWS)))
+    {						/* Impossible cond */
+      zero_result_cause= having_value == Item::COND_FALSE ?
+                           "Impossible HAVING" : "Impossible WHERE";
+      error= 0;
+      DBUG_RETURN(0);
+    }
   }
 
   /* Optimize count(*), min() and max() */
@@ -531,6 +547,24 @@
       }
       zero_result_cause= "Select tables optimized away";
       tables_list= 0;				// All tables resolved
+      /*
+        Extract all table-independent conditions and replace the WHERE
+        clause with them. All other conditions were computed by opt_sum_query
+        and the MIN/MAX/COUNT function(s) have been replaced by constants,
+        so there is no need to compute the whole WHERE clause again.
+        Notice that make_cond_for_table() will always succeed to remove all
+        computed conditions, because opt_sum_query() is applicable only to
+        conjunctions.
+      */
+      if (conds)
+      {
+        COND *table_independent_conds=
+          make_cond_for_table(conds, PSEUDO_TABLE_BITS, 0);
+        DBUG_EXECUTE("where",
+                     print_where(table_independent_conds,
+                                 "where after opt_sum_query()"););
+        conds= table_independent_conds;
+      }
     }
   }
   if (!tables_list)
@@ -683,6 +717,36 @@
     if (old_group_list && !group_list)
       select_distinct= 0;
   }
+  /*
+     Check if we can optimize away GROUP BY/DISTINCT.
+     We can do that if there are no aggregate functions and the
+     fields in DISTINCT clause (if present) and/or columns in GROUP BY
+     (if present) contain direct references to all key parts of
+     an unique index (in whatever order).
+     Note that the unique keys for DISTINCT and GROUP BY should not
+     be the same (as long as they are unique).
+
+     The FROM clause must contain a single non-constant table.
+  */
+  if (tables - const_tables == 1 && (group_list || select_distinct) &&
+      !tmp_table_param.sum_func_count)
+  {
+    if (group_list &&
+       list_contains_unique_index(join_tab[const_tables].table,
+                                 find_field_in_order_list,
+                                 (void *) group_list))
+    {
+      group_list= 0;
+      group= 0;
+    }
+    if (select_distinct &&
+       list_contains_unique_index(join_tab[const_tables].table,
+                                 find_field_in_item_list,
+                                 (void *) &fields_list))
+    {
+      select_distinct= 0;
+    }
+  }
   if (!group_list && group)
   {
     order=0;					// The output has only one row
@@ -876,8 +940,9 @@
 			   group_list ? 0 : select_distinct,
 			   group_list && simple_group,
 			   select_options,
-			   (order == 0 || skip_sort_order) ? select_limit :
-			   HA_POS_ERROR,
+			   (order == 0 || skip_sort_order || 
+                            test(select_options & OPTION_BUFFER_RESULT)) ? 
+                             select_limit : HA_POS_ERROR,
 			   (char *) "")))
       DBUG_RETURN(1);
 
@@ -2090,13 +2155,17 @@
                                 new_fields->null_rejecting);
 	}
 	else if (old->eq_func && new_fields->eq_func &&
-		 (old->val->is_null() || new_fields->val->is_null()))
+		 ((!old->val->used_tables() && old->val->is_null()) || 
+                  new_fields->val->is_null()))
 	{
 	  /* field = expression OR field IS NULL */
 	  old->level= and_level;
 	  old->optimize= KEY_OPTIMIZE_REF_OR_NULL;
-	  /* Remember the NOT NULL value */
-	  if (old->val->is_null())
+	  /*
+            Remember the NOT NULL value unless the value does not depend
+            on other tables.
+          */
+	  if (!old->val->used_tables() && old->val->is_null())
 	    old->val= new_fields->val;
           /* The referred expression can be NULL: */ 
           old->null_rejecting= 0;
@@ -3421,7 +3490,7 @@
 */
 
 bool
-store_val_in_field(Field *field,Item *item)
+store_val_in_field(Field *field, Item *item, enum_check_fields check_flag)
 {
   bool error;
   THD *thd=current_thd;
@@ -3432,7 +3501,7 @@
     with select_insert, which make count_cuted_fields= 1
    */
   enum_check_fields old_count_cuted_fields= thd->count_cuted_fields;
-  thd->count_cuted_fields= CHECK_FIELD_WARN;
+  thd->count_cuted_fields= check_flag;
   error= item->save_in_field(field, 1);
   thd->count_cuted_fields= old_count_cuted_fields;
   return error || cuted_fields != thd->cuted_fields;
@@ -3797,6 +3866,7 @@
 {
   uint i;
   bool statistics= test(!(join->select_options & SELECT_DESCRIBE));
+  bool ordered_set= 0;
   DBUG_ENTER("make_join_readinfo");
 
   for (i=join->const_tables ; i < join->tables ; i++)
@@ -3806,6 +3876,22 @@
     tab->read_record.table= table;
     tab->read_record.file=table->file;
     tab->next_select=sub_select;		/* normal select */
+
+    /*
+      Determine if the set is already ordered for ORDER BY, so it can 
+      disable join cache because it will change the ordering of the results.
+      Code handles sort table that is at any location (not only first after 
+      the const tables) despite the fact that it's currently prohibited.
+    */
+    if (!ordered_set && 
+        (table == join->sort_by_table &&
+         (!join->order || join->skip_sort_order ||
+          test_if_skip_sort_order(tab, join->order, join->select_limit,
+                                  1))
+        ) ||
+        (join->sort_by_table == (TABLE *) 1 && i != join->const_tables))
+      ordered_set= 1;
+
     switch (tab->type) {
     case JT_SYSTEM:				// Only happens with left join
       table->status=STATUS_NO_RECORD;
@@ -3876,10 +3962,11 @@
     case JT_ALL:
       /*
 	If previous table use cache
+        If the incoming data set is already sorted don't use cache.
       */
       table->status=STATUS_NO_RECORD;
       if (i != join->const_tables && !(options & SELECT_NO_JOIN_CACHE)
&&
-	  tab->use_quick != 2 && !tab->on_expr)
+	  tab->use_quick != 2 && !tab->on_expr && !ordered_set)
       {
 	if ((options & SELECT_DESCRIBE) ||
 	    !join_init_cache(join->thd,join->join_tab+join->const_tables,
@@ -4386,10 +4473,16 @@
   DBUG_RETURN(0);
 }
 
-
+/*
+  used only in JOIN::clear
+*/
 static void clear_tables(JOIN *join)
 {
-  for (uint i=0 ; i < join->tables ; i++)
+  /* 
+    must clear only the non-const tables, as const tables
+    are not re-calculated.
+  */
+  for (uint i=join->const_tables ; i < join->tables ; i++)
     mark_as_null_row(join->table[i]);		// All fields are NULL
 }
 
@@ -4615,10 +4708,8 @@
     DBUG_EXECUTE("info", print_where(conds, "after remove"););
   }
   else
-  {
     *cond_value= Item::COND_TRUE;
-    select->prep_where= 0;
-  }
+
   DBUG_RETURN(conds);
 }
 
@@ -4712,7 +4803,7 @@
       Field *field=((Item_field*) args[0])->field;
       if (field->flags & AUTO_INCREMENT_FLAG &&
!field->table->maybe_null &&
 	  (thd->options & OPTION_AUTO_IS_NULL) &&
-	  thd->insert_id())
+	  thd->insert_id() && thd->substitute_null_with_insert_id)
       {
 #ifdef HAVE_QUERY_CACHE
 	query_cache_abort(&thd->net);
@@ -4726,7 +4817,7 @@
 	  cond=new_cond;
 	  cond->fix_fields(thd, 0, &cond);
 	}
-	thd->insert_id(0);		// Clear for next request
+	thd->substitute_null_with_insert_id= FALSE;   // Clear for next request
       }
       /* fix to replace 'NULL' dates with '0' (shreeve@stripped) */
       else if (((field->type() == FIELD_TYPE_DATE) ||
@@ -5180,12 +5271,14 @@
 		       param->group_length : 0,
 		       NullS))
   {
-    bitmap_clear_bit(&temp_pool, temp_pool_slot);
+    if (temp_pool_slot != MY_BIT_NONE)
+      bitmap_clear_bit(&temp_pool, temp_pool_slot);
     DBUG_RETURN(NULL);				/* purecov: inspected */
   }
   if (!(param->copy_field=copy=new Copy_field[field_count]))
   {
-    bitmap_clear_bit(&temp_pool, temp_pool_slot);
+    if (temp_pool_slot != MY_BIT_NONE)
+      bitmap_clear_bit(&temp_pool, temp_pool_slot);
     my_free((gptr) table,MYF(0));		/* purecov: inspected */
     DBUG_RETURN(NULL);				/* purecov: inspected */
   }
@@ -5523,6 +5616,11 @@
       keyinfo->key_length+=  key_part_info->length;
     }
   }
+  else
+  {
+    set_if_smaller(table->max_rows, rows_limit);
+    param->end_write_records= rows_limit;
+  }
 
   if (distinct && field_count != param->hidden_field_count)
   {
@@ -5537,8 +5635,6 @@
     null_pack_length-=hidden_null_pack_length;
     keyinfo->key_parts= ((field_count-param->hidden_field_count)+
 			 test(null_pack_length));
-    set_if_smaller(table->max_rows, rows_limit);
-    param->end_write_records= rows_limit;
     table->distinct=1;
     table->keys=1;
     if (blob_count)
@@ -5605,7 +5701,8 @@
   */
   *table->blob_field= 0;
   free_tmp_table(thd,table);                    /* purecov: inspected */
-  bitmap_clear_bit(&temp_pool, temp_pool_slot);
+  if (temp_pool_slot != MY_BIT_NONE)
+    bitmap_clear_bit(&temp_pool, temp_pool_slot);
   DBUG_RETURN(NULL);				/* purecov: inspected */
 }
 
@@ -5768,7 +5865,8 @@
   my_free((gptr) entry->record[0],MYF(0));
   free_io_cache(entry);
 
-  bitmap_clear_bit(&temp_pool, entry->temp_pool_slot);
+  if (entry->temp_pool_slot != MY_BIT_NONE)
+    bitmap_clear_bit(&temp_pool, entry->temp_pool_slot);
 
   my_free((gptr) entry,MYF(0));
   thd->proc_info=save_proc_info;
@@ -6735,8 +6833,13 @@
 	{
 	  if (!join->first_record)
 	  {
+            List_iterator_fast<Item> it(*join->fields);
+            Item *item;
 	    /* No matching rows for group function */
 	    join->clear();
+
+            while ((item= it++))
+              item->no_rows_in_result();
 	  }
 	  if (join->having && join->having->val_int() == 0)
 	    error= -1;				// Didn't satisfy having
@@ -7090,7 +7193,7 @@
 	    field->real_type() != FIELD_TYPE_VAR_STRING &&
 	    (field->type() != FIELD_TYPE_FLOAT || field->decimals() == 0))
 	{
-	  return !store_val_in_field(field,right_item);
+	  return !store_val_in_field(field, right_item, CHECK_FIELD_WARN);
 	}
       }
     }
@@ -7364,6 +7467,140 @@
   }
   return best;
 }
+
+
+/*
+  Check if GROUP BY/DISTINCT can be optimized away because the set is 
+  already known to be distinct.
+  
+  SYNOPSIS
+    list_contains_unique_index ()
+    table                The table to operate on.
+    find_func            function to iterate over the list and search
+                         for a field
+  
+  DESCRIPTION
+    Used in removing the GROUP BY/DISTINCT of the following types of
+    statements:
+      SELECT [DISTINCT] <unique_key_cols>... FROM <single_table_ref>
+        [GROUP BY <unique_key_cols>,...]
+
+    If (a,b,c is distinct)
+      then <any combination of a,b,c>,{whatever} is also distinct
+
+    This function checks if all the key parts of any of the unique keys
+    of the table are referenced by a list : either the select list 
+    through find_field_in_item_list or GROUP BY list through
+    find_field_in_order_list.
+    If the above holds then we can safely remove the GROUP BY/DISTINCT,
+    as no result set can be more distinct than an unique key.
+  
+  RETURN VALUE
+    1                    found
+    0                    not found.
+*/
+
+static bool
+list_contains_unique_index(TABLE *table,
+                          bool (*find_func) (Field *, void *), void *data)
+{
+  for (uint keynr= 0; keynr < table->keys; keynr++)
+  {
+    if (keynr == table->primary_key ||
+         (table->key_info[keynr].flags & HA_NOSAME))
+    {
+      KEY *keyinfo= table->key_info + keynr;
+      KEY_PART_INFO *key_part, *key_part_end;
+
+      for (key_part=keyinfo->key_part,
+           key_part_end=key_part+ keyinfo->key_parts;
+           key_part < key_part_end;
+           key_part++)
+      {
+        if (!find_func(key_part->field, data))
+          break;
+      }
+      if (key_part == key_part_end)
+        return 1;
+    }
+  }
+  return 0;
+}
+
+
+/*
+  Helper function for list_contains_unique_index.
+  Find a field reference in a list of ORDER structures.
+  
+  SYNOPSIS
+    find_field_in_order_list ()
+    field                The field to search for.
+    data                 ORDER *.The list to search in
+  
+  DESCRIPTION
+    Finds a direct reference of the Field in the list.
+  
+  RETURN VALUE
+    1                    found
+    0                    not found.
+*/
+
+static bool
+find_field_in_order_list (Field *field, void *data)
+{
+  ORDER *group= (ORDER *) data;
+  bool part_found= 0;
+  for (ORDER *tmp_group= group; tmp_group; tmp_group=tmp_group->next)
+  {
+    Item *item= (*tmp_group->item)->real_item();
+    if (item->type() == Item::FIELD_ITEM &&
+        ((Item_field*) item)->field->eq(field))
+    {
+      part_found= 1;
+      break;
+    }
+  }
+  return part_found;
+}
+
+
+/*
+  Helper function for list_contains_unique_index.
+  Find a field reference in a dynamic list of Items.
+  
+  SYNOPSIS
+    find_field_in_item_list ()
+    field in             The field to search for.
+    data  in             List<Item> *.The list to search in
+  
+  DESCRIPTION
+    Finds a direct reference of the Field in the list.
+  
+  RETURN VALUE
+    1                    found
+    0                    not found.
+*/
+
+static bool
+find_field_in_item_list (Field *field, void *data)
+{
+  List<Item> *fields= (List<Item> *) data;
+  bool part_found= 0;
+  List_iterator<Item> li(*fields);
+  Item *item;
+
+  while ((item= li++))
+  {
+    if (item->type() == Item::FIELD_ITEM &&
+        ((Item_field*) item)->field->eq(field))
+    {
+      part_found= 1;
+      break;
+    }
+  }
+  return part_found;
+}
+
 
 /*
   Test if we can skip the ORDER BY by using an index.

--- 1.70/mysql-test/r/ctype_utf8.result	2006-08-16 09:31:29 +05:00
+++ 1.71/mysql-test/r/ctype_utf8.result	2006-08-16 09:31:29 +05:00
@@ -1155,3 +1155,188 @@
 Table	Op	Msg_type	Msg_text
 test.t1	check	status	OK
 drop table t1;
+SET NAMES utf8;
+CREATE TABLE t1 (id int PRIMARY KEY,
+a varchar(16) collate utf8_unicode_ci NOT NULL default '',
+b int,
+f varchar(128) default 'XXX',
+INDEX (a(4))
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+INSERT INTO t1(id, a, b) VALUES
+(1, 'cccc', 50), (2, 'cccc', 70), (3, 'cccc', 30),
+(4, 'cccc', 30), (5, 'cccc', 20), (6, 'bbbbbb', 40),
+(7, 'dddd', 30), (8, 'aaaa', 10), (9, 'aaaa', 50),
+(10, 'eeeee', 40), (11, 'bbbbbb', 60);
+SELECT id, a, b FROM t1;
+id	a	b
+1	cccc	50
+2	cccc	70
+3	cccc	30
+4	cccc	30
+5	cccc	20
+6	bbbbbb	40
+7	dddd	30
+8	aaaa	10
+9	aaaa	50
+10	eeeee	40
+11	bbbbbb	60
+SELECT id, a, b FROM t1 WHERE a BETWEEN 'aaaa' AND 'bbbbbb';
+id	a	b
+8	aaaa	10
+9	aaaa	50
+6	bbbbbb	40
+11	bbbbbb	60
+SELECT id, a FROM t1 WHERE a='bbbbbb';
+id	a
+6	bbbbbb
+11	bbbbbb
+SELECT id, a FROM t1 WHERE a='bbbbbb' ORDER BY b;
+id	a
+6	bbbbbb
+11	bbbbbb
+DROP TABLE t1;
+SET NAMES utf8;
+CREATE TABLE t1 (
+a CHAR(13) DEFAULT '',
+INDEX(a)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
+INSERT INTO t1 VALUES 
+('Käli Käli 2-4'), ('Käli Käli 2-4'),
+('Käli Käli 2+4'), ('Käli Käli 2+4'),
+('Käli Käli 2-6'), ('Käli Käli 2-6');
+INSERT INTO t1 SELECT * FROM t1;
+CREATE TABLE t2 (
+a CHAR(13) DEFAULT '',
+INDEX(a)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;
+INSERT INTO t2 VALUES
+('Kali Kali 2-4'), ('Kali Kali 2-4'),
+('Kali Kali 2+4'), ('Kali Kali 2+4'),
+('Kali Kali 2-6'), ('Kali Kali 2-6');
+INSERT INTO t2 SELECT * FROM t2;
+SELECT a FROM t1 WHERE a LIKE 'Käli Käli 2+4';
+a
+Käli Käli 2+4
+Käli Käli 2+4
+Käli Käli 2+4
+Käli Käli 2+4
+SELECT a FROM t2 WHERE a LIKE 'Kali Kali 2+4';
+a
+Kali Kali 2+4
+Kali Kali 2+4
+Kali Kali 2+4
+Kali Kali 2+4
+EXPLAIN SELECT a FROM t1 WHERE a LIKE 'Käli Käli 2+4';
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	range	a	a	40	NULL	4	Using where; Using index
+EXPLAIN SELECT a FROM t1 WHERE a = 'Käli Käli 2+4';
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	ref	a	a	40	const	4	Using where; Using index
+EXPLAIN SELECT a FROM t2 WHERE a LIKE 'Kali Kali 2+4';
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t2	range	a	a	14	NULL	4	Using where; Using index
+EXPLAIN SELECT a FROM t2 WHERE a = 'Kali Kali 2+4';
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t2	ref	a	a	14	const	4	Using where; Using index
+DROP TABLE t1,t2;
+CREATE TABLE t1 (
+a char(255) DEFAULT '', 
+KEY(a(10))
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
+INSERT INTO t1 VALUES ('Käli Käli 2-4');
+SELECT * FROM t1 WHERE a LIKE 'Käli Käli 2%';
+a
+Käli Käli 2-4
+INSERT INTO t1 VALUES ('Käli Käli 2-4');
+SELECT * FROM t1 WHERE a LIKE 'Käli Käli 2%';
+a
+Käli Käli 2-4
+Käli Käli 2-4
+DROP TABLE t1;
+CREATE TABLE t1 (
+a char(255) DEFAULT ''
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
+INSERT INTO t1 VALUES ('Käli Käli 2-4');
+INSERT INTO t1 VALUES ('Käli Käli 2-4');
+SELECT * FROM t1 WHERE a LIKE 'Käli Käli 2%';
+a
+Käli Käli 2-4
+Käli Käli 2-4
+ALTER TABLE t1 ADD KEY (a(10));
+SELECT * FROM t1 WHERE a LIKE 'Käli Käli 2%';
+a
+Käli Käli 2-4
+Käli Käli 2-4
+DROP TABLE t1;
+SET NAMES latin2;
+CREATE TABLE t1 (
+id int(11) NOT NULL default '0',
+tid int(11) NOT NULL default '0',
+val text NOT NULL,
+INDEX idx(tid, val(10))
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+INSERT INTO t1 VALUES
+(40988,72,'VOLNÝ ADSL'),(41009,72,'VOLNÝ ADSL'),
+(41032,72,'VOLNÝ ADSL'),(41038,72,'VOLNÝ ADSL'),
+(41063,72,'VOLNÝ ADSL'),(41537,72,'VOLNÝ ADSL Office'),
+(42141,72,'VOLNÝ ADSL'),(42565,72,'VOLNÝ ADSL Combi'),
+(42749,72,'VOLNÝ ADSL'),(44205,72,'VOLNÝ ADSL');
+SELECT * FROM t1 WHERE tid=72 and val LIKE 'VOLNY ADSL';
+id	tid	val
+40988	72	VOLNÝ ADSL
+41009	72	VOLNÝ ADSL
+41032	72	VOLNÝ ADSL
+41038	72	VOLNÝ ADSL
+41063	72	VOLNÝ ADSL
+42141	72	VOLNÝ ADSL
+42749	72	VOLNÝ ADSL
+44205	72	VOLNÝ ADSL
+SELECT * FROM t1 WHERE tid=72 and val LIKE 'VOLNÝ ADSL';
+id	tid	val
+40988	72	VOLNÝ ADSL
+41009	72	VOLNÝ ADSL
+41032	72	VOLNÝ ADSL
+41038	72	VOLNÝ ADSL
+41063	72	VOLNÝ ADSL
+42141	72	VOLNÝ ADSL
+42749	72	VOLNÝ ADSL
+44205	72	VOLNÝ ADSL
+SELECT * FROM t1 WHERE tid=72 and val LIKE '%VOLNÝ ADSL';
+id	tid	val
+40988	72	VOLNÝ ADSL
+41009	72	VOLNÝ ADSL
+41032	72	VOLNÝ ADSL
+41038	72	VOLNÝ ADSL
+41063	72	VOLNÝ ADSL
+42141	72	VOLNÝ ADSL
+42749	72	VOLNÝ ADSL
+44205	72	VOLNÝ ADSL
+ALTER TABLE t1 DROP KEY idx;
+ALTER TABLE t1 ADD KEY idx (tid,val(11));
+SELECT * FROM t1 WHERE tid=72 and val LIKE 'VOLNÝ ADSL';
+id	tid	val
+40988	72	VOLNÝ ADSL
+41009	72	VOLNÝ ADSL
+41032	72	VOLNÝ ADSL
+41038	72	VOLNÝ ADSL
+41063	72	VOLNÝ ADSL
+42141	72	VOLNÝ ADSL
+42749	72	VOLNÝ ADSL
+44205	72	VOLNÝ ADSL
+DROP TABLE t1;
+create table t1(a char(200) collate utf8_unicode_ci NOT NULL default '')
+default charset=utf8 collate=utf8_unicode_ci;
+insert into t1 values (unhex('65')), (unhex('C3A9')), (unhex('65'));
+explain select distinct a from t1;
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	ALL	NULL	NULL	NULL	NULL	3	Using temporary
+select distinct a from t1;
+a
+e
+explain select a from t1 group by a;
+id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
+1	SIMPLE	t1	ALL	NULL	NULL	NULL	NULL	3	Using temporary; Using filesort
+select a from t1 group by a;
+a
+e
+drop table t1;

--- 1.72/mysql-test/t/ctype_utf8.test	2006-08-16 09:31:29 +05:00
+++ 1.73/mysql-test/t/ctype_utf8.test	2006-08-16 09:31:29 +05:00
@@ -944,4 +944,132 @@
 check table t1;
 drop table t1;
 
+#
+# Bug#14896: Comparison with a key in a partial index over mb chararacter field
+#
+
+SET NAMES utf8;
+CREATE TABLE t1 (id int PRIMARY KEY,
+                 a varchar(16) collate utf8_unicode_ci NOT NULL default '',
+                 b int,
+                 f varchar(128) default 'XXX',
+                 INDEX (a(4))
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
+INSERT INTO t1(id, a, b) VALUES
+  (1, 'cccc', 50), (2, 'cccc', 70), (3, 'cccc', 30),
+  (4, 'cccc', 30), (5, 'cccc', 20), (6, 'bbbbbb', 40),
+  (7, 'dddd', 30), (8, 'aaaa', 10), (9, 'aaaa', 50),
+  (10, 'eeeee', 40), (11, 'bbbbbb', 60);
+
+SELECT id, a, b FROM t1;
+
+SELECT id, a, b FROM t1 WHERE a BETWEEN 'aaaa' AND 'bbbbbb';
+
+SELECT id, a FROM t1 WHERE a='bbbbbb';
+SELECT id, a FROM t1 WHERE a='bbbbbb' ORDER BY b;
+
+DROP TABLE t1;
+
+#
+# Bug#16674: LIKE predicate for a utf8 character set column
+#
+
+SET NAMES utf8;
+
+CREATE TABLE t1 (
+  a CHAR(13) DEFAULT '',
+  INDEX(a)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
+INSERT INTO t1 VALUES 
+ ('Käli Käli 2-4'), ('Käli Käli 2-4'),
+ ('Käli Käli 2+4'), ('Käli Käli 2+4'),
+ ('Käli Käli 2-6'), ('Käli Käli 2-6');
+INSERT INTO t1 SELECT * FROM t1;
+
+CREATE TABLE t2 (
+  a CHAR(13) DEFAULT '',
+  INDEX(a)
+) ENGINE=MyISAM DEFAULT CHARSET=latin1 COLLATE=latin1_general_ci;
+
+INSERT INTO t2 VALUES
+ ('Kali Kali 2-4'), ('Kali Kali 2-4'),
+ ('Kali Kali 2+4'), ('Kali Kali 2+4'),
+ ('Kali Kali 2-6'), ('Kali Kali 2-6');
+INSERT INTO t2 SELECT * FROM t2;
+
+SELECT a FROM t1 WHERE a LIKE 'Käli Käli 2+4';
+SELECT a FROM t2 WHERE a LIKE 'Kali Kali 2+4';
+
+EXPLAIN SELECT a FROM t1 WHERE a LIKE 'Käli Käli 2+4';
+EXPLAIN SELECT a FROM t1 WHERE a = 'Käli Käli 2+4';
+EXPLAIN SELECT a FROM t2 WHERE a LIKE 'Kali Kali 2+4';
+EXPLAIN SELECT a FROM t2 WHERE a = 'Kali Kali 2+4';
+
+DROP TABLE t1,t2;
+
+CREATE TABLE t1 (
+  a char(255) DEFAULT '', 
+  KEY(a(10))
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
+INSERT INTO t1 VALUES ('Käli Käli 2-4');
+SELECT * FROM t1 WHERE a LIKE 'Käli Käli 2%';
+INSERT INTO t1 VALUES ('Käli Käli 2-4');
+SELECT * FROM t1 WHERE a LIKE 'Käli Käli 2%';
+DROP TABLE t1;
+
+CREATE TABLE t1 (
+  a char(255) DEFAULT ''
+) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
+INSERT INTO t1 VALUES ('Käli Käli 2-4');
+INSERT INTO t1 VALUES ('Käli Käli 2-4');
+SELECT * FROM t1 WHERE a LIKE 'Käli Käli 2%';
+ALTER TABLE t1 ADD KEY (a(10));
+SELECT * FROM t1 WHERE a LIKE 'Käli Käli 2%';
+DROP TABLE t1;
+
+#
+# Bug#18359: LIKE predicate for a 'utf8' text column with a partial index
+#            (see bug #16674 as well)
+#
+
+SET NAMES latin2;
+
+CREATE TABLE t1 (
+  id int(11) NOT NULL default '0',
+  tid int(11) NOT NULL default '0',
+  val text NOT NULL,
+  INDEX idx(tid, val(10))
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
+INSERT INTO t1 VALUES
+  (40988,72,'VOLNÝ ADSL'),(41009,72,'VOLNÝ ADSL'),
+  (41032,72,'VOLNÝ ADSL'),(41038,72,'VOLNÝ ADSL'),
+  (41063,72,'VOLNÝ ADSL'),(41537,72,'VOLNÝ ADSL Office'),
+  (42141,72,'VOLNÝ ADSL'),(42565,72,'VOLNÝ ADSL Combi'),
+  (42749,72,'VOLNÝ ADSL'),(44205,72,'VOLNÝ ADSL');
+
+SELECT * FROM t1 WHERE tid=72 and val LIKE 'VOLNY ADSL'; 
+SELECT * FROM t1 WHERE tid=72 and val LIKE 'VOLNÝ ADSL'; 
+SELECT * FROM t1 WHERE tid=72 and val LIKE '%VOLNÝ ADSL'; 
+
+ALTER TABLE t1 DROP KEY idx;
+ALTER TABLE t1 ADD KEY idx (tid,val(11));
+
+SELECT * FROM t1 WHERE tid=72 and val LIKE 'VOLNÝ ADSL'; 
+
+DROP TABLE t1;
+
+#
+# Bug 20709: problem with utf8 fields in temporary tables
+#
+
+create table t1(a char(200) collate utf8_unicode_ci NOT NULL default '')
+  default charset=utf8 collate=utf8_unicode_ci;
+insert into t1 values (unhex('65')), (unhex('C3A9')), (unhex('65'));
+explain select distinct a from t1;
+select distinct a from t1;
+explain select a from t1 group by a;
+select a from t1 group by a;
+drop table t1;
+
 # End of 4.1 tests
Thread
bk commit into 4.1 tree (bar:1.2534)bar16 Aug