diff options
author | Sergey Petrunia <sergefp@mysql.com> | 2009-03-11 23:13:39 +0300 |
---|---|---|
committer | Sergey Petrunia <sergefp@mysql.com> | 2009-03-11 23:13:39 +0300 |
commit | fd35040890864139eba77c16c4292c28eadf0f10 (patch) | |
tree | f959e15dc0af30eb3066527235b89ec71e837e9f | |
parent | 989ee96b64b9eb510a62857c0ca7ef7dbdf28f2b (diff) | |
download | mariadb-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.result | 73 | ||||
-rw-r--r-- | mysql-test/t/index_merge_myisam.test | 75 | ||||
-rw-r--r-- | sql/mysql_priv.h | 21 | ||||
-rw-r--r-- | sql/mysqld.cc | 34 | ||||
-rw-r--r-- | sql/opt_range.cc | 14 | ||||
-rw-r--r-- | sql/set_var.cc | 61 | ||||
-rw-r--r-- | sql/set_var.h | 6 | ||||
-rw-r--r-- | sql/strfunc.cc | 182 |
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, ¬_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, ¬_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) |