summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Petrunia <sergefp@mysql.com>2009-03-11 23:13:39 +0300
committerSergey Petrunia <sergefp@mysql.com>2009-03-11 23:13:39 +0300
commitfd35040890864139eba77c16c4292c28eadf0f10 (patch)
treef959e15dc0af30eb3066527235b89ec71e837e9f
parent989ee96b64b9eb510a62857c0ca7ef7dbdf28f2b (diff)
downloadmariadb-git-fd35040890864139eba77c16c4292c28eadf0f10.tar.gz
Change optimizer_switch from no_xxx to xxx=on/xx=off.
mysql-test/r/index_merge_myisam.result: Testcases mysql-test/t/index_merge_myisam.test: Testcases sql/strfunc.cc: Change optimizer_switch from no_xxx to xxx=on/xx=off. - Add functions to parse the new syntax
-rw-r--r--mysql-test/r/index_merge_myisam.result73
-rw-r--r--mysql-test/t/index_merge_myisam.test75
-rw-r--r--sql/mysql_priv.h21
-rw-r--r--sql/mysqld.cc34
-rw-r--r--sql/opt_range.cc14
-rw-r--r--sql/set_var.cc61
-rw-r--r--sql/set_var.h6
-rw-r--r--sql/strfunc.cc182
8 files changed, 388 insertions, 78 deletions
diff --git a/mysql-test/r/index_merge_myisam.result b/mysql-test/r/index_merge_myisam.result
index cc2110ced32..ab112257492 100644
--- a/mysql-test/r/index_merge_myisam.result
+++ b/mysql-test/r/index_merge_myisam.result
@@ -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=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 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;
diff --git a/mysql-test/t/index_merge_myisam.test b/mysql-test/t/index_merge_myisam.test
index 13997cfd427..d6945ec9cf4 100644
--- a/mysql-test/t/index_merge_myisam.test
+++ b/mysql-test/t/index_merge_myisam.test
@@ -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.a+100*C.a, 'foo', 'bar'
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;
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 3b8e65d532f..f2ce7471922 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -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(Item **items, uint nitems);
/* 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,
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 5fdcd04de87..2c465452c13 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -302,16 +302,17 @@ TYPELIB sql_mode_typelib= { array_elements(sql_mode_names)-1,"",
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:
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 719ff2a4a7e..1184068a377 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -2387,7 +2387,7 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
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 *thd, key_map keys_to_use,
}
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(PARAM *param, SEL_IMERGE *imerge,
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(PARAM *param, SEL_IMERGE *imerge,
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(PARAM *param, SEL_IMERGE *imerge,
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_intersect(const PARAM *param, SEL_TREE *tree,
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_intersect(PARAM *param,
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)
diff --git a/sql/set_var.cc b/sql/set_var.cc
index e964d8f957c..e631b8fdba7 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -3926,17 +3926,17 @@ symbolic_mode_representation(THD *thd, ulonglong val, LEX_STRING *rep)
{
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::value_ptr(THD *thd, enum_var_type type,
}
-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;
}
diff --git a/sql/set_var.h b/sql/set_var.h
index f07facde0b0..eee4bc51b7e 100644
--- a/sql/set_var.h
+++ b/sql/set_var.h
@@ -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);
diff --git a/sql/strfunc.cc b/sql/strfunc.cc
index c03365cfc2b..aad91a2a16a 100644
--- a/sql/strfunc.cc
+++ b/sql/strfunc.cc
@@ -88,6 +88,188 @@ ulonglong find_set(TYPELIB *lib, const char *str, uint length, CHARSET_INFO *cs,
}
+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)