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,
/** makes @c find_type() require the whole name, no prefix */
#define FIND_TYPE_NO_PREFIX (1 << 0)
/** always implicitely on, so unused, but old code may pass it */
#define FIND_TYPE_NO_OVERWRITE (1 << 1)
/** makes @c find_type() accept a number */
#define FIND_TYPE_ALLOW_NUMBER (1 << 2)
/** makes @c find_type() treat ',' as terminator */
#define FIND_TYPE_NO_OVERWRITE 0
/** makes @c find_type() accept a number. Not used either */
#define FIND_TYPE_ALLOW_NUMBER 0
/** makes @c find_type() treat ',' and '=' as terminators */
#define FIND_TYPE_COMMA_TERM (1 << 3)
extern int find_type(const char *x, const TYPELIB *typelib, unsigned int flags);
......
......@@ -52,6 +52,10 @@ set session optimizer_switch="default";
select @@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
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;
ERROR 42000: Incorrect argument type to variable 'optimizer_switch'
set global optimizer_switch=1e1;
......
......@@ -34,6 +34,9 @@ select * from information_schema.session_variables where variable_name='optimize
set session optimizer_switch="default";
select @@session.optimizer_switch;
set optimizer_switch = replace(@@optimizer_switch, '=off', '=on');
select @@optimizer_switch;
#
# incorrect assignments
#
......
......@@ -20,7 +20,8 @@
#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)
{
......@@ -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.
@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 flags flags to tune behaviour: a combination of
FIND_TYPE_NO_PREFIX
FIND_TYPE_ALLOW_NUMBER
FIND_TYPE_COMMA_TERM.
FIND_TYPE_NO_OVERWRITE can be passed but is
superfluous (is always implicitely on).
@param eol a pointer to the end of the string.
@retval
-1 Too many matching values
......@@ -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 UNINIT_VAR(findpos); /* guarded by find */
const char *UNINIT_VAR(termptr);
const char *i;
const char *j;
DBUG_ENTER("find_type");
DBUG_PRINT("enter",("x: '%s' lib: 0x%lx", x, (long) typelib));
CHARSET_INFO *cs= &my_charset_latin1;
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)
{
DBUG_PRINT("exit",("no count"));
......@@ -95,42 +99,52 @@ int find_type(const char *x, const TYPELIB *typelib, uint flags)
find=0;
for (pos=0 ; (j=typelib->type_names[pos]) ; pos++)
{
for (i=x ;
*i && (!(flags & FIND_TYPE_COMMA_TERM) || !is_field_separator(*i)) &&
my_toupper(&my_charset_latin1,*i) ==
my_toupper(&my_charset_latin1,*j) ; i++, j++) ;
for (i=*x ;
i < eol && !is_field_separator(flags, *i) &&
my_toupper(cs, *i) == my_toupper(cs, *j) ; i++, j++) ;
if (! *j)
{
while (*i == ' ')
while (i < eol && *i == ' ')
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);
}
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)))
{
find++;
findpos=pos;
termptr=i;
}
}
if (find == 0 && (flags & FIND_TYPE_ALLOW_NUMBER) && x[0] == '#' &&
strend(x)[-1] == '#' &&
(findpos=atoi(x+1)-1) >= 0 && (uint) findpos < typelib->count)
find=1;
else if (find == 0 || ! x[0])
if (find == 0 || *x == eol)
{
DBUG_PRINT("exit",("Couldn't find type"));
DBUG_RETURN(0);
}
else if (find != 1 || (flags & FIND_TYPE_NO_PREFIX))
{
DBUG_PRINT("exit",("Too many possybilities"));
DBUG_PRINT("exit",("Too many possibilities"));
DBUG_RETURN(-1);
}
*x= termptr;
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
......@@ -198,7 +212,7 @@ my_ulonglong find_typeset(char *x, TYPELIB *lib, int *err)
{
(*err)++;
i= x;
while (*x && !is_field_separator(*x))
while (*x && *x != ',')
x++;
if (x[0] && x[1]) /* skip separator if found */
x++;
......@@ -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
*/
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(pos, lib, FIND_TYPE_COMMA_TERM);
for (; pos != end && *pos != '=' && *pos !=',' ; pos++);
*strpos= pos;
uint find= find_type_eol(pos, lib,
FIND_TYPE_COMMA_TERM | FIND_TYPE_NO_PREFIX, end);
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