Commit 4cd19779 authored by Sergei Golubchik's avatar Sergei Golubchik

MDEV-69 SET optimizer_switch = REPLACE(...) causes ER_WRONG_VALUE_FOR_VAR

find_set() in typelib.c expected a zero-terminated string

include/typelib.h:
  disable unused flags
parent 1433621c
...@@ -35,10 +35,10 @@ extern int find_type_or_exit(const char *x, TYPELIB *typelib, ...@@ -35,10 +35,10 @@ extern int find_type_or_exit(const char *x, TYPELIB *typelib,
/** makes @c find_type() require the whole name, no prefix */ /** makes @c find_type() require the whole name, no prefix */
#define FIND_TYPE_NO_PREFIX (1 << 0) #define FIND_TYPE_NO_PREFIX (1 << 0)
/** always implicitely on, so unused, but old code may pass it */ /** always implicitely on, so unused, but old code may pass it */
#define FIND_TYPE_NO_OVERWRITE (1 << 1) #define FIND_TYPE_NO_OVERWRITE 0
/** makes @c find_type() accept a number */ /** makes @c find_type() accept a number. Not used either */
#define FIND_TYPE_ALLOW_NUMBER (1 << 2) #define FIND_TYPE_ALLOW_NUMBER 0
/** makes @c find_type() treat ',' as terminator */ /** makes @c find_type() treat ',' and '=' as terminators */
#define FIND_TYPE_COMMA_TERM (1 << 3) #define FIND_TYPE_COMMA_TERM (1 << 3)
extern int find_type(const char *x, const TYPELIB *typelib, unsigned int flags); extern int find_type(const char *x, const TYPELIB *typelib, unsigned int flags);
......
...@@ -52,6 +52,10 @@ set session optimizer_switch="default"; ...@@ -52,6 +52,10 @@ set session optimizer_switch="default";
select @@session.optimizer_switch; select @@session.optimizer_switch;
@@session.optimizer_switch @@session.optimizer_switch
index_merge=off,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off index_merge=off,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=off,engine_condition_pushdown=off,index_condition_pushdown=off,derived_merge=off,derived_with_keys=off,firstmatch=off,loosescan=off,materialization=off,in_to_exists=off,semijoin=off,partial_match_rowid_merge=off,partial_match_table_scan=off,subquery_cache=off,mrr=off,mrr_cost_based=off,mrr_sort_keys=off,outer_join_with_cache=off,semijoin_with_cache=off,join_cache_incremental=off,join_cache_hashed=off,join_cache_bka=off,optimize_join_buffer_size=off,table_elimination=off
set optimizer_switch = replace(@@optimizer_switch, '=off', '=on');
select @@optimizer_switch;
@@optimizer_switch
index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,index_merge_sort_intersection=on,engine_condition_pushdown=on,index_condition_pushdown=on,derived_merge=on,derived_with_keys=on,firstmatch=on,loosescan=on,materialization=on,in_to_exists=on,semijoin=on,partial_match_rowid_merge=on,partial_match_table_scan=on,subquery_cache=on,mrr=on,mrr_cost_based=on,mrr_sort_keys=on,outer_join_with_cache=on,semijoin_with_cache=on,join_cache_incremental=on,join_cache_hashed=on,join_cache_bka=on,optimize_join_buffer_size=on,table_elimination=on
set global optimizer_switch=1.1; set global optimizer_switch=1.1;
ERROR 42000: Incorrect argument type to variable 'optimizer_switch' ERROR 42000: Incorrect argument type to variable 'optimizer_switch'
set global optimizer_switch=1e1; set global optimizer_switch=1e1;
......
...@@ -34,6 +34,9 @@ select * from information_schema.session_variables where variable_name='optimize ...@@ -34,6 +34,9 @@ select * from information_schema.session_variables where variable_name='optimize
set session optimizer_switch="default"; set session optimizer_switch="default";
select @@session.optimizer_switch; select @@session.optimizer_switch;
set optimizer_switch = replace(@@optimizer_switch, '=off', '=on');
select @@optimizer_switch;
# #
# incorrect assignments # incorrect assignments
# #
......
...@@ -20,7 +20,8 @@ ...@@ -20,7 +20,8 @@
#include <m_ctype.h> #include <m_ctype.h>
#define is_field_separator(X) ((X) == ',' || (X) == '=') #define is_field_separator(F, X) \
((F & FIND_TYPE_COMMA_TERM) && ((X) == ',' || (X) == '='))
int find_type_with_warning(const char *x, TYPELIB *typelib, const char *option) int find_type_with_warning(const char *x, TYPELIB *typelib, const char *option)
{ {
...@@ -58,14 +59,14 @@ int find_type_or_exit(const char *x, TYPELIB *typelib, const char *option) ...@@ -58,14 +59,14 @@ int find_type_or_exit(const char *x, TYPELIB *typelib, const char *option)
/** /**
Search after a string in a list of strings. Endspace in x is not compared. Search after a string in a list of strings. Endspace in x is not compared.
@param x String to find @param x pointer to string to find
(not necessarily zero-terminated).
by return it'll be advanced to point to the terminator.
@param typelib TYPELIB (struct of pointer to values + count) @param typelib TYPELIB (struct of pointer to values + count)
@param flags flags to tune behaviour: a combination of @param flags flags to tune behaviour: a combination of
FIND_TYPE_NO_PREFIX FIND_TYPE_NO_PREFIX
FIND_TYPE_ALLOW_NUMBER
FIND_TYPE_COMMA_TERM. FIND_TYPE_COMMA_TERM.
FIND_TYPE_NO_OVERWRITE can be passed but is @param eol a pointer to the end of the string.
superfluous (is always implicitely on).
@retval @retval
-1 Too many matching values -1 Too many matching values
...@@ -76,17 +77,20 @@ int find_type_or_exit(const char *x, TYPELIB *typelib, const char *option) ...@@ -76,17 +77,20 @@ int find_type_or_exit(const char *x, TYPELIB *typelib, const char *option)
*/ */
int find_type(const char *x, const TYPELIB *typelib, uint flags) static int find_type_eol(const char **x, const TYPELIB *typelib, uint flags,
const char *eol)
{ {
int find,pos; int find,pos;
int UNINIT_VAR(findpos); /* guarded by find */ int UNINIT_VAR(findpos); /* guarded by find */
const char *UNINIT_VAR(termptr);
const char *i; const char *i;
const char *j; const char *j;
DBUG_ENTER("find_type"); CHARSET_INFO *cs= &my_charset_latin1;
DBUG_PRINT("enter",("x: '%s' lib: 0x%lx", x, (long) typelib)); DBUG_ENTER("find_type_eol");
DBUG_PRINT("enter",("x: '%s' lib: 0x%lx", *x, (long) typelib));
DBUG_ASSERT(!(flags & ~(FIND_TYPE_NO_PREFIX | FIND_TYPE_COMMA_TERM)));
DBUG_ASSERT(!(flags & ~(FIND_TYPE_NO_PREFIX | FIND_TYPE_ALLOW_NUMBER |
FIND_TYPE_NO_OVERWRITE | FIND_TYPE_COMMA_TERM)));
if (!typelib->count) if (!typelib->count)
{ {
DBUG_PRINT("exit",("no count")); DBUG_PRINT("exit",("no count"));
...@@ -95,42 +99,52 @@ int find_type(const char *x, const TYPELIB *typelib, uint flags) ...@@ -95,42 +99,52 @@ int find_type(const char *x, const TYPELIB *typelib, uint flags)
find=0; find=0;
for (pos=0 ; (j=typelib->type_names[pos]) ; pos++) for (pos=0 ; (j=typelib->type_names[pos]) ; pos++)
{ {
for (i=x ; for (i=*x ;
*i && (!(flags & FIND_TYPE_COMMA_TERM) || !is_field_separator(*i)) && i < eol && !is_field_separator(flags, *i) &&
my_toupper(&my_charset_latin1,*i) == my_toupper(cs, *i) == my_toupper(cs, *j) ; i++, j++) ;
my_toupper(&my_charset_latin1,*j) ; i++, j++) ;
if (! *j) if (! *j)
{ {
while (*i == ' ') while (i < eol && *i == ' ')
i++; /* skip_end_space */ i++; /* skip_end_space */
if (! *i || ((flags & FIND_TYPE_COMMA_TERM) && is_field_separator(*i))) if (i >= eol || is_field_separator(flags, *i))
{
*x= i;
DBUG_RETURN(pos+1); DBUG_RETURN(pos+1);
} }
if ((!*i && }
(!(flags & FIND_TYPE_COMMA_TERM) || !is_field_separator(*i))) && if ((i >= eol && !is_field_separator(flags, *i)) &&
(!*j || !(flags & FIND_TYPE_NO_PREFIX))) (!*j || !(flags & FIND_TYPE_NO_PREFIX)))
{ {
find++; find++;
findpos=pos; findpos=pos;
termptr=i;
} }
} }
if (find == 0 && (flags & FIND_TYPE_ALLOW_NUMBER) && x[0] == '#' && if (find == 0 || *x == eol)
strend(x)[-1] == '#' &&
(findpos=atoi(x+1)-1) >= 0 && (uint) findpos < typelib->count)
find=1;
else if (find == 0 || ! x[0])
{ {
DBUG_PRINT("exit",("Couldn't find type")); DBUG_PRINT("exit",("Couldn't find type"));
DBUG_RETURN(0); DBUG_RETURN(0);
} }
else if (find != 1 || (flags & FIND_TYPE_NO_PREFIX)) else if (find != 1 || (flags & FIND_TYPE_NO_PREFIX))
{ {
DBUG_PRINT("exit",("Too many possybilities")); DBUG_PRINT("exit",("Too many possibilities"));
DBUG_RETURN(-1); DBUG_RETURN(-1);
} }
*x= termptr;
DBUG_RETURN(findpos+1); DBUG_RETURN(findpos+1);
} /* find_type */ } /* find_type_eol */
/**
Search after a string in a list of strings. Endspace in x is not compared.
Same as find_type_eol, but for zero-terminated strings,
and without advancing the pointer.
*/
int find_type(const char *x, const TYPELIB *typelib, uint flags)
{
return find_type_eol(&x, typelib, flags, x + strlen(x));
}
/** /**
Get name of type nr Get name of type nr
...@@ -198,7 +212,7 @@ my_ulonglong find_typeset(char *x, TYPELIB *lib, int *err) ...@@ -198,7 +212,7 @@ my_ulonglong find_typeset(char *x, TYPELIB *lib, int *err)
{ {
(*err)++; (*err)++;
i= x; i= x;
while (*x && !is_field_separator(*x)) while (*x && *x != ',')
x++; x++;
if (x[0] && x[1]) /* skip separator if found */ if (x[0] && x[1]) /* skip separator if found */
x++; x++;
...@@ -283,12 +297,10 @@ static TYPELIB on_off_default_typelib= {array_elements(on_off_default_names)-1, ...@@ -283,12 +297,10 @@ static TYPELIB on_off_default_typelib= {array_elements(on_off_default_names)-1,
>0 Offset+1 in typelib for matched name >0 Offset+1 in typelib for matched name
*/ */
static uint parse_name(const TYPELIB *lib, const char **strpos, const char *end) static uint parse_name(const TYPELIB *lib, const char **pos, const char *end)
{ {
const char *pos= *strpos; uint find= find_type_eol(pos, lib,
uint find= find_type(pos, lib, FIND_TYPE_COMMA_TERM); FIND_TYPE_COMMA_TERM | FIND_TYPE_NO_PREFIX, end);
for (; pos != end && *pos != '=' && *pos !=',' ; pos++);
*strpos= pos;
return find; return find;
} }
......
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