List:Commits« Previous MessageNext Message »
From:Sergey Petrunia Date:March 11 2009 8:15pm
Subject:bzr push into mysql-5.1-bugteam branch (sergefp:2807 to 2808)
View as plain text  
 2808 Sergey Petrunia	2009-03-11
      Change optimizer_switch from no_xxx to xxx=on/xx=off.
modified:
  mysql-test/r/index_merge_myisam.result
  mysql-test/t/index_merge_myisam.test
  sql/mysql_priv.h
  sql/mysqld.cc
  sql/opt_range.cc
  sql/set_var.cc
  sql/set_var.h
  sql/strfunc.cc

 2807 Sergey Petrunia	2009-03-10
      Post-merge fixes
modified:
  sql/mysqld.cc

=== modified file 'mysql-test/r/index_merge_myisam.result'
--- a/mysql-test/r/index_merge_myisam.result	2009-02-23 16:16:48 +0000
+++ b/mysql-test/r/index_merge_myisam.result	2009-03-11 20:13:39 +0000
@@ -1392,11 +1392,46 @@ WHERE
 `TESTID`='' AND `UCCHECK`='';
 drop table t1;
 #
-# @@optimizer_switch support and check
+# Generic @@optimizer_switch tests (move those into a separate file if
+#  we get another @@optimizer_switch user)
 #
 select @@optimizer_switch;
 @@optimizer_switch
-
+index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on
+set optimizer_switch='index_merge=off,index_merge_union=off';
+select @@optimizer_switch;
+@@optimizer_switch
+index_merge=off,index_merge_union=off,index_merge_sort_union=on,index_merge_intersection=on
+set optimizer_switch='index_merge_union=on';
+select @@optimizer_switch;
+@@optimizer_switch
+index_merge=off,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on
+set optimizer_switch='default,index_merge_sort_union=off';
+select @@optimizer_switch;
+@@optimizer_switch
+index_merge=on,index_merge_union=on,index_merge_sort_union=off,index_merge_intersection=on
+set optimizer_switch=4;
+ERROR 42000: Variable 'optimizer_switch' can't be set to the value of '4'
+set optimizer_switch=NULL;
+ERROR 42000: Variable 'optimizer_switch' can't be set to the value of 'NULL'
+set optimizer_switch='default,index_merge';
+ERROR 42000: Variable 'optimizer_switch' can't be set to the value of 'index_merge'
+set optimizer_switch='index_merge=index_merge';
+ERROR 42000: Variable 'optimizer_switch' can't be set to the value of 'index_merge=index_merge'
+set optimizer_switch='index_merge=on,but...';
+ERROR 42000: Variable 'optimizer_switch' can't be set to the value of 'but...'
+set optimizer_switch='index_merge=';
+ERROR 42000: Variable 'optimizer_switch' can't be set to the value of 'index_merge='
+set optimizer_switch='index_merge';
+ERROR 42000: Variable 'optimizer_switch' can't be set to the value of 'index_merge'
+set optimizer_switch='on';
+ERROR 42000: Variable 'optimizer_switch' can't be set to the value of 'on'
+#
+# Check index_merge's @@optimizer_switch flags
+#
+select @@optimizer_switch;
+@@optimizer_switch
+index_merge=on,index_merge_union=on,index_merge_sort_union=off,index_merge_intersection=on
 create table t0 (a int);
 insert into t0 values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9);
 create table t1 (a int, b int, c int, filler char(100), 
@@ -1412,44 +1447,44 @@ explain select * from t1 where a=1 or b=
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 1	SIMPLE	t1	index_merge	a,b	a,b	5,5	NULL	2	Using union(a,b); Using where
 This should use ALL:
-set optimizer_switch='no_index_merge';
+set optimizer_switch='default,index_merge=off';
 explain select * from t1 where a=1 or b=1;
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 1	SIMPLE	t1	ALL	a,b	NULL	NULL	NULL	1000	Using where
 This should use sort-union:
-set optimizer_switch='no_index_merge_union';
+set optimizer_switch='default,index_merge_union=off';
 explain select * from t1 where a=1 or b=1;
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 1	SIMPLE	t1	index_merge	a,b	a,b	5,5	NULL	2	Using sort_union(a,b); Using where
 This will use sort-union:
-set optimizer_switch='';
+set optimizer_switch=default;
 explain select * from t1 where a<1 or b <1;
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 1	SIMPLE	t1	index_merge	a,b	a,b	5,5	NULL	38	Using sort_union(a,b); Using where
 This should use ALL:
-set optimizer_switch='no_index_merge_sort_union';
+set optimizer_switch='default,index_merge_sort_union=off';
 explain select * from t1 where a<1 or b <1;
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 1	SIMPLE	t1	ALL	a,b	NULL	NULL	NULL	1000	Using where
 This should use ALL:
-set optimizer_switch='no_index_merge';
+set optimizer_switch='default,index_merge=off';
 explain select * from t1 where a<1 or b <1;
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 1	SIMPLE	t1	ALL	a,b	NULL	NULL	NULL	1000	Using where
 This will use sort-union:
-set optimizer_switch='no_index_merge_union';
+set optimizer_switch='default,index_merge_union=off';
 explain select * from t1 where a<1 or b <1;
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 1	SIMPLE	t1	index_merge	a,b	a,b	5,5	NULL	38	Using sort_union(a,b); Using where
 alter table t1 add d int, add key(d);
 update t1 set d=a;
 This will use sort_union:
-set optimizer_switch='';
+set optimizer_switch=default;
 explain select * from t1 where (a=3 or b in (1,2)) and (c=3 or d=4);
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 1	SIMPLE	t1	index_merge	a,b,c,d	a,b	5,5	NULL	3	Using sort_union(a,b); Using where
 And if we disable sort_union, union:
-set optimizer_switch='no_index_merge_sort_union';
+set optimizer_switch='default,index_merge_sort_union=off';
 explain select * from t1 where (a=3 or b in (1,2)) and (c=3 or d=4);
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 1	SIMPLE	t1	index_merge	a,b,c,d	c,d	5,5	NULL	100	Using union(c,d); Using where
@@ -1463,48 +1498,48 @@ insert into t1 
 select A.a+10*B.a, A.a+10*B.a, A.a+10*B.a+100*C.a, 'foo', 'bar' 
 from t0 A, t0 B, t0 C, t0 D where D.a<5;
 This should be intersect:
-set optimizer_switch='';
+set optimizer_switch=default;
 explain select * from t1 where a=10 and b=10;
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 1	SIMPLE	t1	index_merge	a,b	a,b	5,5	NULL	1	Using intersect(a,b); Using where
 No intersect when index_merge is disabled:
-set optimizer_switch='no_index_merge';
+set optimizer_switch='default,index_merge=off';
 explain select * from t1 where a=10 and b=10;
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 1	SIMPLE	t1	ref	a,b	a	5	const	49	Using where
 No intersect if it is disabled:
-set optimizer_switch='no_index_merge_intersection';
+set optimizer_switch='default,index_merge_intersection=off';
 explain select * from t1 where a=10 and b=10;
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 1	SIMPLE	t1	ref	a,b	a	5	const	49	Using where
 Do intersect when union was disabled
-set optimizer_switch='no_index_merge_union';
+set optimizer_switch='default,index_merge_union=off';
 explain select * from t1 where a=10 and b=10;
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 1	SIMPLE	t1	index_merge	a,b	a,b	5,5	NULL	1	Using intersect(a,b); Using where
 Do intersect when sort_union was disabled
-set optimizer_switch='no_index_merge_sort_union';
+set optimizer_switch='default,index_merge_sort_union=off';
 explain select * from t1 where a=10 and b=10;
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 1	SIMPLE	t1	index_merge	a,b	a,b	5,5	NULL	1	Using intersect(a,b); Using where
 This will use intersection inside a union:
-set optimizer_switch='';
+set optimizer_switch=default;
 explain select * from t1 where a=10 and b=10 or c=10;
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 1	SIMPLE	t1	index_merge	a,b,c	a,b,c	5,5,5	NULL	6	Using union(intersect(a,b),c); Using where
 Should be only union left:
-set optimizer_switch='no_index_merge_intersection';
+set optimizer_switch='default,index_merge_intersection=off';
 explain select * from t1 where a=10 and b=10 or c=10;
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 1	SIMPLE	t1	index_merge	a,b,c	a,c	5,5	NULL	54	Using union(a,c); Using where
 This will switch to sort-union (intersection will be gone, too,
 thats a known limitation:
-set optimizer_switch='no_index_merge_union';
+set optimizer_switch='default,index_merge_union=off';
 explain select * from t1 where a=10 and b=10 or c=10;
 id	select_type	table	type	possible_keys	key	key_len	ref	rows	Extra
 1	SIMPLE	t1	index_merge	a,b,c	a,c	5,5	NULL	54	Using sort_union(a,c); Using where
 set optimizer_switch=default;
 show variables like 'optimizer_switch';
 Variable_name	Value
-optimizer_switch	
+optimizer_switch	index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on
 drop table t0, t1;

=== modified file 'mysql-test/t/index_merge_myisam.test'
--- a/mysql-test/t/index_merge_myisam.test	2009-02-23 16:16:48 +0000
+++ b/mysql-test/t/index_merge_myisam.test	2009-03-11 20:13:39 +0000
@@ -21,7 +21,47 @@ let $merge_table_support= 1;
 --source include/index_merge_ror_cpk.inc
 
 --echo #
---echo # @@optimizer_switch support and check
+--echo # Generic @@optimizer_switch tests (move those into a separate file if
+--echo #  we get another @@optimizer_switch user)
+--echo #
+
+select @@optimizer_switch;
+
+set optimizer_switch='index_merge=off,index_merge_union=off';
+select @@optimizer_switch;
+
+set optimizer_switch='index_merge_union=on';
+select @@optimizer_switch;
+
+set optimizer_switch='default,index_merge_sort_union=off';
+select @@optimizer_switch;
+
+--error ER_WRONG_VALUE_FOR_VAR
+set optimizer_switch=4;
+
+--error ER_WRONG_VALUE_FOR_VAR
+set optimizer_switch=NULL;
+
+--error ER_WRONG_VALUE_FOR_VAR
+set optimizer_switch='default,index_merge';
+
+--error ER_WRONG_VALUE_FOR_VAR
+set optimizer_switch='index_merge=index_merge';
+
+--error ER_WRONG_VALUE_FOR_VAR
+set optimizer_switch='index_merge=on,but...';
+
+--error ER_WRONG_VALUE_FOR_VAR
+set optimizer_switch='index_merge=';
+
+--error ER_WRONG_VALUE_FOR_VAR
+set optimizer_switch='index_merge';
+
+--error ER_WRONG_VALUE_FOR_VAR
+set optimizer_switch='on';
+
+--echo #
+--echo # Check index_merge's @@optimizer_switch flags
 --echo #
 select @@optimizer_switch;
 
@@ -40,39 +80,39 @@ from t0 A, t0 B, t0 C; 
 explain select * from t1 where a=1 or b=1;
 
 --echo This should use ALL:
-set optimizer_switch='no_index_merge';
+set optimizer_switch='default,index_merge=off';
 explain select * from t1 where a=1 or b=1;
 
 --echo This should use sort-union:
-set optimizer_switch='no_index_merge_union';
+set optimizer_switch='default,index_merge_union=off';
 explain select * from t1 where a=1 or b=1;
 
 --echo This will use sort-union:
-set optimizer_switch='';
+set optimizer_switch=default;
 explain select * from t1 where a<1 or b <1;
 
 --echo This should use ALL:
-set optimizer_switch='no_index_merge_sort_union';
+set optimizer_switch='default,index_merge_sort_union=off';
 explain select * from t1 where a<1 or b <1;
 
 
 --echo This should use ALL:
-set optimizer_switch='no_index_merge';
+set optimizer_switch='default,index_merge=off';
 explain select * from t1 where a<1 or b <1;
 
 --echo This will use sort-union:
-set optimizer_switch='no_index_merge_union';
+set optimizer_switch='default,index_merge_union=off';
 explain select * from t1 where a<1 or b <1;
 
 alter table t1 add d int, add key(d);
 update t1 set d=a;
 
 --echo This will use sort_union:
-set optimizer_switch='';
+set optimizer_switch=default;
 explain select * from t1 where (a=3 or b in (1,2)) and (c=3 or d=4);
 
 --echo And if we disable sort_union, union:
-set optimizer_switch='no_index_merge_sort_union';
+set optimizer_switch='default,index_merge_sort_union=off';
 explain select * from t1 where (a=3 or b in (1,2)) and (c=3 or d=4);
 
 drop table t1;
@@ -89,40 +129,41 @@ select A.a+10*B.a, A.a+10*B.a, A.a+10*B.
 from t0 A, t0 B, t0 C, t0 D where D.a<5;
 
 --echo This should be intersect:
-set optimizer_switch='';
+set optimizer_switch=default;
 explain select * from t1 where a=10 and b=10;
 
 --echo No intersect when index_merge is disabled:
-set optimizer_switch='no_index_merge';
+set optimizer_switch='default,index_merge=off';
 explain select * from t1 where a=10 and b=10;
 
 --echo No intersect if it is disabled:
-set optimizer_switch='no_index_merge_intersection';
+set optimizer_switch='default,index_merge_intersection=off';
 explain select * from t1 where a=10 and b=10;
 
 --echo Do intersect when union was disabled
-set optimizer_switch='no_index_merge_union';
+set optimizer_switch='default,index_merge_union=off';
 explain select * from t1 where a=10 and b=10;
 
 --echo Do intersect when sort_union was disabled
-set optimizer_switch='no_index_merge_sort_union';
+set optimizer_switch='default,index_merge_sort_union=off';
 explain select * from t1 where a=10 and b=10;
 
 # Now take union-of-intersection and see how we can disable parts of it
 --echo This will use intersection inside a union:
-set optimizer_switch='';
+set optimizer_switch=default;
 explain select * from t1 where a=10 and b=10 or c=10;
 
 --echo Should be only union left:
-set optimizer_switch='no_index_merge_intersection';
+set optimizer_switch='default,index_merge_intersection=off';
 explain select * from t1 where a=10 and b=10 or c=10;
 
 --echo This will switch to sort-union (intersection will be gone, too,
 --echo   thats a known limitation:
-set optimizer_switch='no_index_merge_union';
+set optimizer_switch='default,index_merge_union=off';
 explain select * from t1 where a=10 and b=10 or c=10;
 
 set optimizer_switch=default;
 show variables like 'optimizer_switch';
+
 drop table t0, t1;
 

=== modified file 'sql/mysql_priv.h'
--- a/sql/mysql_priv.h	2009-03-09 21:53:38 +0000
+++ b/sql/mysql_priv.h	2009-03-11 20:13:39 +0000
@@ -523,11 +523,18 @@ protected:
 #define MODE_NO_ENGINE_SUBSTITUTION     (MODE_HIGH_NOT_PRECEDENCE*2)
 #define MODE_PAD_CHAR_TO_FULL_LENGTH    (ULL(1) << 31)
 
-/* @@optimizer_switch flags */
-#define OPTIMIZER_SWITCH_NO_INDEX_MERGE 1
-#define OPTIMIZER_SWITCH_NO_INDEX_MERGE_UNION 2
-#define OPTIMIZER_SWITCH_NO_INDEX_MERGE_SORT_UNION 4
-#define OPTIMIZER_SWITCH_NO_INDEX_MERGE_INTERSECT 8
+/* @@optimizer_switch flags. These must be in sync with optimizer_switch_typelib */
+#define OPTIMIZER_SWITCH_INDEX_MERGE 1
+#define OPTIMIZER_SWITCH_INDEX_MERGE_UNION 2
+#define OPTIMIZER_SWITCH_INDEX_MERGE_SORT_UNION 4
+#define OPTIMIZER_SWITCH_INDEX_MERGE_INTERSECT 8
+#define OPTIMIZER_SWITCH_LAST 16
+
+#define OPTIMIZER_SWITCH_DEFAULT (OPTIMIZER_SWITCH_INDEX_MERGE | \
+                                  OPTIMIZER_SWITCH_INDEX_MERGE_UNION | \
+                                  OPTIMIZER_SWITCH_INDEX_MERGE_SORT_UNION | \
+                                  OPTIMIZER_SWITCH_INDEX_MERGE_INTERSECT)
+
 
 /*
   Replication uses 8 bytes to store SQL_MODE in the binary log. The day you
@@ -1831,6 +1838,10 @@ extern enum_field_types agg_field_type(I
 /* strfunc.cc */
 ulonglong find_set(TYPELIB *lib, const char *x, uint length, CHARSET_INFO *cs,
 		   char **err_pos, uint *err_len, bool *set_warning);
+ulonglong find_set_from_flags(TYPELIB *lib, uint default_set,
+                              ulonglong cur_set, ulonglong default_set,
+                              const char *str, uint length, CHARSET_INFO *cs,
+                              char **err_pos, uint *err_len, bool *set_warning);
 uint find_type(const TYPELIB *lib, const char *find, uint length,
                bool part_match);
 uint find_type2(const TYPELIB *lib, const char *find, uint length,

=== modified file 'sql/mysqld.cc'
--- a/sql/mysqld.cc	2009-03-10 08:49:30 +0000
+++ b/sql/mysqld.cc	2009-03-11 20:13:39 +0000
@@ -302,16 +302,17 @@ TYPELIB sql_mode_typelib= { array_elemen
 
 static const char *optimizer_switch_names[]=
 {
-  "no_index_merge","no_index_merge_union","no_index_merge_sort_union", 
-  "no_index_merge_intersection", NullS
+  "index_merge","index_merge_union","index_merge_sort_union", 
+  "index_merge_intersection", "default", NullS
 };
 /* Corresponding defines are named OPTIMIZER_SWITCH_XXX */
 static const unsigned int optimizer_switch_names_len[]=
 {
-  sizeof("no_index_merge") - 1,
-  sizeof("no_index_merge_union") - 1,
-  sizeof("ni_index_merge_sort_union") - 1,
-  sizeof("no_index_merge_intersection") - 1
+  sizeof("index_merge") - 1,
+  sizeof("index_merge_union") - 1,
+  sizeof("index_merge_sort_union") - 1,
+  sizeof("index_merge_intersection") - 1,
+  sizeof("default") - 1
 };
 TYPELIB optimizer_switch_typelib= { array_elements(optimizer_switch_names)-1,"",
                                     optimizer_switch_names,
@@ -7656,7 +7657,8 @@ static int mysql_init_variables(void)
     when collecting index statistics for MyISAM tables.
   */
   global_system_variables.myisam_stats_method= MI_STATS_METHOD_NULLS_NOT_EQUAL;
-
+  
+  global_system_variables.optimizer_switch= OPTIMIZER_SWITCH_DEFAULT;
   /* Variables that depends on compile options */
 #ifndef DBUG_OFF
   default_dbug_option=IF_WIN("d:t:i:O,\\mysqld.trace",
@@ -8252,12 +8254,22 @@ mysqld_get_one_option(int optid,
   }
   case OPT_OPTIMIZER_SWITCH:
   {
+    bool not_used;
+    char *error= 0;
+    uint error_len= 0;
     optimizer_switch_str= argument;
     global_system_variables.optimizer_switch=
-      find_bit_type_or_exit(argument, &optimizer_switch_typelib, opt->name, 
-                            &error);
-    if (error)
-      return 1;
+      (ulong)find_set_from_flags(&optimizer_switch_typelib, 
+                                 optimizer_switch_typelib.count, 
+                                 global_system_variables.optimizer_switch,
+                                 global_system_variables.optimizer_switch,
+                                 argument, strlen(argument), NULL,
+                                 &error, &error_len, &not_used);
+     if (error)
+     {
+       fprintf(stderr, "Invalid optimizer_switch flag: %s\n", error);
+       return 1;
+     }
     break;
   }
   case OPT_ONE_THREAD:

=== modified file 'sql/opt_range.cc'
--- a/sql/opt_range.cc	2009-03-09 21:53:38 +0000
+++ b/sql/opt_range.cc	2009-03-11 20:13:39 +0000
@@ -2387,7 +2387,7 @@ int SQL_SELECT::test_quick_select(THD *t
           table deletes.
         */
         if ((thd->lex->sql_command != SQLCOM_DELETE) && 
-             !optimizer_flag(thd, OPTIMIZER_SWITCH_NO_INDEX_MERGE))
+             optimizer_flag(thd, OPTIMIZER_SWITCH_INDEX_MERGE))
         {
           /*
             Get best non-covering ROR-intersection plan and prepare data for
@@ -2411,7 +2411,7 @@ int SQL_SELECT::test_quick_select(THD *t
       }
       else
       {
-        if (!optimizer_flag(thd, OPTIMIZER_SWITCH_NO_INDEX_MERGE))
+        if (optimizer_flag(thd, OPTIMIZER_SWITCH_INDEX_MERGE))
         {
           /* Try creating index_merge/ROR-union scan. */
           SEL_IMERGE *imerge;
@@ -3778,7 +3778,7 @@ TABLE_READ_PLAN *get_best_disjunct_quick
     disabled in @@optimizer_switch
   */
   if (all_scans_rors && 
-      !optimizer_flag(param->thd, OPTIMIZER_SWITCH_NO_INDEX_MERGE_UNION))
+      optimizer_flag(param->thd, OPTIMIZER_SWITCH_INDEX_MERGE_UNION))
   {
     roru_read_plans= (TABLE_READ_PLAN**)range_scans;
     goto skip_to_ror_scan;
@@ -3798,7 +3798,7 @@ TABLE_READ_PLAN *get_best_disjunct_quick
   DBUG_PRINT("info",("index_merge cost with rowid-to-row scan: %g",
                      imerge_cost));
   if (imerge_cost > read_time || 
-      optimizer_flag(param->thd, OPTIMIZER_SWITCH_NO_INDEX_MERGE_SORT_UNION))
+      !optimizer_flag(param->thd, OPTIMIZER_SWITCH_INDEX_MERGE_SORT_UNION))
   {
     goto build_ror_index_merge;
   }
@@ -3839,7 +3839,7 @@ TABLE_READ_PLAN *get_best_disjunct_quick
 build_ror_index_merge:
   if (!all_scans_ror_able || 
       param->thd->lex->sql_command == SQLCOM_DELETE ||
-      optimizer_flag(param->thd, OPTIMIZER_SWITCH_NO_INDEX_MERGE_UNION))
+      !optimizer_flag(param->thd, OPTIMIZER_SWITCH_INDEX_MERGE_UNION))
     DBUG_RETURN(imerge_trp);
 
   /* Ok, it is possible to build a ROR-union, try it. */
@@ -4513,7 +4513,7 @@ TRP_ROR_INTERSECT *get_best_ror_intersec
   DBUG_ENTER("get_best_ror_intersect");
 
   if ((tree->n_ror_scans < 2) || !param->table->file->stats.records ||
-      optimizer_flag(param->thd, OPTIMIZER_SWITCH_NO_INDEX_MERGE_INTERSECT))
+      !optimizer_flag(param->thd, OPTIMIZER_SWITCH_INDEX_MERGE_INTERSECT))
     DBUG_RETURN(NULL);
 
   /*
@@ -4703,7 +4703,7 @@ TRP_ROR_INTERSECT *get_best_covering_ror
   ROR_SCAN_INFO **ror_scans_end= tree->ror_scans_end;
   DBUG_ENTER("get_best_covering_ror_intersect");
 
-  if (optimizer_flag(param->thd, OPTIMIZER_SWITCH_NO_INDEX_MERGE_INTERSECT))
+  if (!optimizer_flag(param->thd, OPTIMIZER_SWITCH_INDEX_MERGE_INTERSECT))
     DBUG_RETURN(NULL);
 
   for (ROR_SCAN_INFO **scan= tree->ror_scans; scan != ror_scans_end; ++scan)

=== modified file 'sql/set_var.cc'
--- a/sql/set_var.cc	2009-03-09 21:53:38 +0000
+++ b/sql/set_var.cc	2009-03-11 20:13:39 +0000
@@ -3926,17 +3926,17 @@ symbolic_mode_representation(THD *thd, u
 {
   char buff[STRING_BUFFER_USUAL_SIZE*8];
   String tmp(buff, sizeof(buff), &my_charset_latin1);
-
+  int i;
+  ulonglong bit;
   tmp.length(0);
-
-  for (uint i= 0; val; val>>= 1, i++)
+ 
+  for (i= 0, bit=1; bit != OPTIMIZER_SWITCH_LAST; i++, bit= bit << 1)
   {
-    if (val & 1)
-    {
-      tmp.append(optimizer_switch_typelib.type_names[i],
-                 optimizer_switch_typelib.type_lengths[i]);
-      tmp.append(',');
-    }
+    tmp.append(optimizer_switch_typelib.type_names[i],
+               optimizer_switch_typelib.type_lengths[i]);
+    tmp.append('=');
+    tmp.append((val & bit)? "on":"off");
+    tmp.append(',');
   }
 
   if (tmp.length())
@@ -3961,12 +3961,45 @@ uchar *sys_var_thd_optimizer_switch::val
 }
 
 
-void sys_var_thd_optimizer_switch::set_default(THD *thd, enum_var_type type)
+/*
+  Check (and actually parse) string representation of @@optimizer_switch.
+*/
+
+bool sys_var_thd_optimizer_switch::check(THD *thd, set_var *var)
 {
-  if (type == OPT_GLOBAL)
-    global_system_variables.*offset= 0;
-  else
-    thd->variables.*offset= global_system_variables.*offset;
+  bool not_used;
+  char buff[STRING_BUFFER_USUAL_SIZE], *error= 0;
+  uint error_len= 0;
+  String str(buff, sizeof(buff), system_charset_info), *res;
+
+  if (!(res= var->value->val_str(&str)))
+  {
+    strmov(buff, "NULL");
+    goto err;
+  }
+  
+  if (res->length() == 0)
+  {
+    buff[0]= 0;
+    goto err;
+  }
+
+  var->save_result.ulong_value= 
+    (ulong)find_set_from_flags(&optimizer_switch_typelib, 
+                               optimizer_switch_typelib.count, 
+                               thd->variables.optimizer_switch,
+                               global_system_variables.optimizer_switch,
+                               res->c_ptr(), res->length(), NULL,
+                               &error, &error_len, &not_used);
+  if (error_len)
+  {
+    strmake(buff, error, min(sizeof(buff) - 1, error_len));
+    goto err;
+  }
+  return FALSE;
+err:
+  my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), name, buff);
+  return TRUE;
 }
 
 

=== modified file 'sql/set_var.h'
--- a/sql/set_var.h	2009-02-23 16:16:48 +0000
+++ b/sql/set_var.h	2009-03-11 20:13:39 +0000
@@ -539,11 +539,7 @@ public:
                                ulong SV::*offset_arg)
     :sys_var_thd_enum(chain, name_arg, offset_arg, &optimizer_switch_typelib)
   {}
-  bool check(THD *thd, set_var *var)
-  {
-    return check_set(thd, var, enum_names);
-  }
-  void set_default(THD *thd, enum_var_type type);
+  bool check(THD *thd, set_var *var);
   uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base);
   static bool symbolic_mode_representation(THD *thd, ulonglong sql_mode,
                                            LEX_STRING *rep);

=== modified file 'sql/strfunc.cc'
--- a/sql/strfunc.cc	2007-08-13 13:11:25 +0000
+++ b/sql/strfunc.cc	2009-03-11 20:13:39 +0000
@@ -88,6 +88,188 @@ ulonglong find_set(TYPELIB *lib, const c
 }
 
 
+static const char *on_off_default_names[]=
+{
+  "off","on","default", NullS
+};
+
+static const unsigned int on_off_default_names_len[]=
+{
+  sizeof("off") - 1,
+  sizeof("on") - 1,
+  sizeof("default") - 1
+};
+
+static TYPELIB on_off_default_typelib= {array_elements(on_off_default_names)-1,
+                                        "", on_off_default_names,
+                                        (unsigned int *)on_off_default_names_len};
+
+
+/*
+  Given a string, find the first field_separator char, minding the charset
+*/
+
+static uint parse_name(TYPELIB *lib, const char **strpos, const char *end, 
+                       CHARSET_INFO *cs)
+{
+  const char *pos= *strpos;
+  const char *start= pos;
+
+  /* Find the length */
+  if (cs && cs->mbminlen > 1)
+  {
+    int mblen= 0;
+    for ( ; pos < end; pos+= mblen)
+    {
+      my_wc_t wc;
+      if ((mblen= cs->cset->mb_wc(cs, &wc, (const uchar *) pos,
+                                           (const uchar *) end)) < 1)
+        mblen= 1; // Not to hang on a wrong multibyte sequence
+      if (wc == (my_wc_t) '=' || wc == (my_wc_t) ',')
+        break;
+    }
+  }
+  else
+    for (; pos != end && *pos != '=' && *pos !=',' ; pos++);
+
+  uint var_len= (uint) (pos - start);
+  /* Determine which flag it is*/
+  uint find= cs ? find_type2(lib, start, var_len, cs) :
+                  find_type(lib, start, var_len, (bool) 0);
+  *strpos= pos;
+  return find;
+}
+
+
+/* Read next character from the buffer in a charset-aware way */
+
+static my_wc_t get_next_char(const char **pos, const char *end, CHARSET_INFO *cs)
+{
+  my_wc_t wc;
+  if (*pos == end)
+      return (my_wc_t)-1;
+
+  if (cs && cs->mbminlen > 1)
+  {
+    int mblen;
+    if ((mblen= cs->cset->mb_wc(cs, &wc, (const uchar *) *pos,
+                                         (const uchar *) end)) < 1)
+      mblen= 1; // Not to hang on a wrong multibyte sequence
+    *pos += mblen;
+    return wc;
+  }
+  else
+    return *((*pos)++);
+}
+
+
+/*
+  Parse a string representation of set of flags
+
+  SYNOPSIS
+    find_set_from_flags()
+      lib               Flag names
+      default_name      Number of "default" in the typelib
+      cur_set           Current set of flags (start from this state)
+      default_set       Default set of flags (use this for assign-default
+                        keyword and flag=default assignments)
+      str	        String representation (see below)
+      length            Length of the above
+      cs                Charset used for the string
+      err_pos	   OUT  If error, set to point to start of wrong set string
+      err_len	   OUT  If error, set to the length of wrong set string
+      set_warning  OUT  TRUE <=> Some string in set couldn't be used
+
+  DESCRIPTION
+    Parse a set of flag assignments, that is, parse a string in form:
+
+      param_name1=value1,param_name2=value2,... 
+    
+    where the names are specified in the TYPELIB, and each value can be
+    either 'on','off', or 'default'. Besides param=val assignments, we
+    support "default" keyword (keyword #default_name in the typelib) which
+    means assign everything the default.
+    
+  RETURN
+    FALSE Ok
+    TRUE  Error
+*/
+
+ulonglong find_set_from_flags(TYPELIB *lib, uint default_name,
+                              ulonglong cur_set, ulonglong default_set,
+                              const char *str, uint length, CHARSET_INFO *cs,
+                              char **err_pos, uint *err_len, bool *set_warning)
+{
+  CHARSET_INFO *strip= cs ? cs : &my_charset_latin1;
+  const char *end= str + strip->cset->lengthsp(strip, str, length);
+  ulonglong flags= cur_set;
+  *err_pos= 0;                  // No error yet
+  if (str != end)
+  {
+    const char *start= str;    
+    for (;;)
+    {
+      my_wc_t chr;
+      const char *pos= start;
+      uint flag, value;
+
+      if (!(flag= parse_name(lib, &pos, end, cs)))
+      {
+        *err_pos= (char*) start;
+        *err_len= pos - start;
+        *set_warning= 1;
+        break;
+      }
+
+      if (flag == default_name)
+      {
+        flags= default_set;
+      }
+      else
+      {
+        if ((chr= get_next_char(&pos, end, cs)) != '=')
+        {
+          *err_pos= (char*)start;
+          *err_len= pos - start;
+          *set_warning= 1;
+          break;
+        }
+
+        if (!(value= parse_name(&on_off_default_typelib, &pos, end, cs)))
+        {
+          *err_pos= (char*) start;
+          *err_len= pos - start;
+          *set_warning= 1;
+          break;
+        }
+        
+        ulonglong bit=  ((longlong) 1 << (flag - 1));
+        if (value == 1) // this is 'xxx=off'
+          flags &= ~bit;
+        else if (value == 2) // this is 'xxx=on' 
+          flags |= bit;
+        else // this is 'xxx=default'
+        {
+          bit= default_set & bit;
+          flags= (flags & ~bit) | bit;
+        }
+      }
+
+      if (pos >= end)
+        break;
+      if ((chr= get_next_char(&pos, end, cs)) != ',')
+      {
+        *err_pos= (char*)start;
+        *err_len= pos - start;
+        *set_warning= 1;
+      }
+      start=pos;
+    }
+  }
+  return flags;
+}
+
+
 /*
   Function to find a string in a TYPELIB
   (Same format as mysys/typelib.c)

Thread
bzr push into mysql-5.1-bugteam branch (sergefp:2807 to 2808)Sergey Petrunia11 Mar