Commit 7877de39 authored by Sergey Petrunia's avatar Sergey Petrunia

Change optimizer_switch from no_xxx to xxx=on/xx=off.

parent 4961e008
......@@ -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;
......@@ -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;
......@@ -523,11 +523,18 @@ class Default_object_creation_ctx : public Object_creation_ctx
#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,
......
......@@ -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:
......
......@@ -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)
......
......@@ -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;
}
......
......@@ -539,11 +539,7 @@ class sys_var_thd_optimizer_switch :public sys_var_thd_enum
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);
......
......@@ -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)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment