2014-01-06 06:22:35 +01:00
|
|
|
/* Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
|
2020-01-26 17:27:13 +01:00
|
|
|
Copyright (c) 2009, 2020, MariaDB Corporation.
|
2003-11-03 13:01:59 +01:00
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
2006-12-23 20:17:15 +01:00
|
|
|
the Free Software Foundation; version 2 of the License.
|
2003-11-03 13:01:59 +01:00
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
2019-05-11 20:29:06 +02:00
|
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
|
2003-11-03 13:01:59 +01:00
|
|
|
|
|
|
|
/* Some useful string utility functions used by the MySQL server */
|
|
|
|
|
2017-06-18 05:42:16 +02:00
|
|
|
#include "mariadb.h"
|
2010-03-31 16:05:33 +02:00
|
|
|
#include "sql_priv.h"
|
|
|
|
#include "unireg.h"
|
|
|
|
#include "strfunc.h"
|
|
|
|
#include "sql_class.h"
|
|
|
|
#include "typelib.h" // TYPELIB
|
|
|
|
#include "m_ctype.h" // my_charset_latin1
|
|
|
|
#include "mysqld.h" // system_charset_info
|
2003-11-03 13:01:59 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
Return bitmap for strings used in a set
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
find_set()
|
|
|
|
lib Strings in set
|
|
|
|
str Strings of set-strings separated by ','
|
|
|
|
err_pos If error, set to point to start of wrong set string
|
|
|
|
err_len If error, set to the length of wrong set string
|
|
|
|
set_warning Set to 1 if some string in set couldn't be used
|
|
|
|
|
|
|
|
NOTE
|
|
|
|
We delete all end space from str before comparison
|
|
|
|
|
|
|
|
RETURN
|
|
|
|
bitmap of all sets found in x.
|
|
|
|
set_warning is set to 1 if there was any sets that couldn't be set
|
|
|
|
*/
|
|
|
|
|
|
|
|
static const char field_separator=',';
|
|
|
|
|
2019-06-26 03:29:44 +02:00
|
|
|
ulonglong find_set(const TYPELIB *lib,
|
|
|
|
const char *str, size_t length, CHARSET_INFO *cs,
|
2004-10-26 10:17:37 +02:00
|
|
|
char **err_pos, uint *err_len, bool *set_warning)
|
2003-11-03 13:01:59 +01:00
|
|
|
{
|
2004-10-26 10:17:37 +02:00
|
|
|
CHARSET_INFO *strip= cs ? cs : &my_charset_latin1;
|
2020-01-26 17:27:13 +01:00
|
|
|
const char *end= str + strip->lengthsp(str, length);
|
2003-11-03 13:01:59 +01:00
|
|
|
ulonglong found= 0;
|
2004-10-26 10:17:37 +02:00
|
|
|
*err_pos= 0; // No error yet
|
2009-12-22 10:35:56 +01:00
|
|
|
*err_len= 0;
|
2003-11-03 13:01:59 +01:00
|
|
|
if (str != end)
|
|
|
|
{
|
|
|
|
const char *start= str;
|
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
const char *pos= start;
|
|
|
|
uint var_len;
|
2004-12-06 17:45:32 +01:00
|
|
|
int mblen= 1;
|
2003-11-03 13:01:59 +01:00
|
|
|
|
2004-12-06 17:45:32 +01:00
|
|
|
if (cs && cs->mbminlen > 1)
|
|
|
|
{
|
|
|
|
for ( ; pos < end; pos+= mblen)
|
|
|
|
{
|
|
|
|
my_wc_t wc;
|
2020-01-26 17:27:13 +01:00
|
|
|
if ((mblen= cs->mb_wc(&wc, (const uchar *) pos,
|
|
|
|
(const uchar *) end)) < 1)
|
2004-12-06 17:45:32 +01:00
|
|
|
mblen= 1; // Not to hang on a wrong multibyte sequence
|
2022-08-10 10:40:37 +02:00
|
|
|
else if (wc == (my_wc_t) field_separator)
|
2004-12-06 17:45:32 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
for (; pos != end && *pos != field_separator; pos++) ;
|
2003-11-03 13:01:59 +01:00
|
|
|
var_len= (uint) (pos - start);
|
2004-10-26 10:17:37 +02:00
|
|
|
uint find= cs ? find_type2(lib, start, var_len, cs) :
|
|
|
|
find_type(lib, start, var_len, (bool) 0);
|
Fix all warnings given by UBSAN
The easiest way to compile and test the server with UBSAN is to run:
./BUILD/compile-pentium64-ubsan
and then run mysql-test-run.
After this commit, one should be able to run this without any UBSAN
warnings. There is still a few compiler warnings that should be fixed
at some point, but these do not expose any real bugs.
The 'special' cases where we disable, suppress or circumvent UBSAN are:
- ref10 source (as here we intentionally do some shifts that UBSAN
complains about.
- x86 version of optimized int#korr() methods. UBSAN do not like unaligned
memory access of integers. Fixed by using byte_order_generic.h when
compiling with UBSAN
- We use smaller thread stack with ASAN and UBSAN, which forced me to
disable a few tests that prints the thread stack size.
- Verifying class types does not work for shared libraries. I added
suppression in mysql-test-run.pl for this case.
- Added '#ifdef WITH_UBSAN' when using integer arithmetic where it is
safe to have overflows (two cases, in item_func.cc).
Things fixed:
- Don't left shift signed values
(byte_order_generic.h, mysqltest.c, item_sum.cc and many more)
- Don't assign not non existing values to enum variables.
- Ensure that bool and enum values are properly initialized in
constructors. This was needed as UBSAN checks that these types has
correct values when one copies an object.
(gcalc_tools.h, ha_partition.cc, item_sum.cc, partition_element.h ...)
- Ensure we do not called handler functions on unallocated objects or
deleted objects.
(events.cc, sql_acl.cc).
- Fixed bugs in Item_sp::Item_sp() where we did not call constructor
on Query_arena object.
- Fixed several cast of objects to an incompatible class!
(Item.cc, Item_buff.cc, item_timefunc.cc, opt_subselect.cc, sql_acl.cc,
sql_select.cc ...)
- Ensure we do not do integer arithmetic that causes over or underflows.
This includes also ++ and -- of integers.
(Item_func.cc, Item_strfunc.cc, item_timefunc.cc, sql_base.cc ...)
- Added JSON_VALUE_UNITIALIZED to json_value_types and ensure that
value_type is initialized to this instead of to -1, which is not a valid
enum value for json_value_types.
- Ensure we do not call memcpy() when second argument could be null.
- Fixed that Item_func_str::make_empty_result() creates an empty string
instead of a null string (safer as it ensures we do not do arithmetic
on null strings).
Other things:
- Changed struct st_position to an OBJECT and added an initialization
function to it to ensure that we do not copy or use uninitialized
members. The change to a class was also motived that we used "struct
st_position" and POSITION randomly trough the code which was
confusing.
- Notably big rewrite in sql_acl.cc to avoid using deleted objects.
- Changed in sql_partition to use '^' instead of '-'. This is safe as
the operator is either 0 or 0x8000000000000000ULL.
- Added check for select_nr < INT_MAX in JOIN::build_explain() to
avoid bug when get_select() could return NULL.
- Reordered elements in POSITION for better alignment.
- Changed sql_test.cc::print_plan() to use pointers instead of objects.
- Fixed bug in find_set() where could could execute '1 << -1'.
- Added variable have_sanitizer, used by mtr. (This variable was before
only in 10.5 and up). It can now have one of two values:
ASAN or UBSAN.
- Moved ~Archive_share() from ha_archive.cc to ha_archive.h and marked
it virtual. This was an effort to get UBSAN to work with loaded storage
engines. I kept the change as the new place is better.
- Added in CONNECT engine COLBLK::SetName(), to get around a wrong cast
in tabutil.cpp.
- Added HAVE_REPLICATION around usage of rgi_slave, to get embedded
server to compile with UBSAN. (Patch from Marko).
- Added #ifdef for powerpc64 to avoid a bug in old gcc versions related
to integer arithmetic.
Changes that should not be needed but had to be done to suppress warnings
from UBSAN:
- Added static_cast<<uint16_t>> around shift to get rid of a LOT of
compiler warnings when using UBSAN.
- Had to change some '/' of 2 base integers to shift to get rid of
some compile time warnings.
Reviewed by:
- Json changes: Alexey Botchkov
- Charset changes in ctype-uca.c: Alexander Barkov
- InnoDB changes & Embedded server: Marko Mäkelä
- sql_acl.cc changes: Vicențiu Ciorbaru
- build_explain() changes: Sergey Petrunia
2021-04-18 14:29:13 +02:00
|
|
|
if (unlikely(!find))
|
2003-11-03 13:01:59 +01:00
|
|
|
{
|
Fix all warnings given by UBSAN
The easiest way to compile and test the server with UBSAN is to run:
./BUILD/compile-pentium64-ubsan
and then run mysql-test-run.
After this commit, one should be able to run this without any UBSAN
warnings. There is still a few compiler warnings that should be fixed
at some point, but these do not expose any real bugs.
The 'special' cases where we disable, suppress or circumvent UBSAN are:
- ref10 source (as here we intentionally do some shifts that UBSAN
complains about.
- x86 version of optimized int#korr() methods. UBSAN do not like unaligned
memory access of integers. Fixed by using byte_order_generic.h when
compiling with UBSAN
- We use smaller thread stack with ASAN and UBSAN, which forced me to
disable a few tests that prints the thread stack size.
- Verifying class types does not work for shared libraries. I added
suppression in mysql-test-run.pl for this case.
- Added '#ifdef WITH_UBSAN' when using integer arithmetic where it is
safe to have overflows (two cases, in item_func.cc).
Things fixed:
- Don't left shift signed values
(byte_order_generic.h, mysqltest.c, item_sum.cc and many more)
- Don't assign not non existing values to enum variables.
- Ensure that bool and enum values are properly initialized in
constructors. This was needed as UBSAN checks that these types has
correct values when one copies an object.
(gcalc_tools.h, ha_partition.cc, item_sum.cc, partition_element.h ...)
- Ensure we do not called handler functions on unallocated objects or
deleted objects.
(events.cc, sql_acl.cc).
- Fixed bugs in Item_sp::Item_sp() where we did not call constructor
on Query_arena object.
- Fixed several cast of objects to an incompatible class!
(Item.cc, Item_buff.cc, item_timefunc.cc, opt_subselect.cc, sql_acl.cc,
sql_select.cc ...)
- Ensure we do not do integer arithmetic that causes over or underflows.
This includes also ++ and -- of integers.
(Item_func.cc, Item_strfunc.cc, item_timefunc.cc, sql_base.cc ...)
- Added JSON_VALUE_UNITIALIZED to json_value_types and ensure that
value_type is initialized to this instead of to -1, which is not a valid
enum value for json_value_types.
- Ensure we do not call memcpy() when second argument could be null.
- Fixed that Item_func_str::make_empty_result() creates an empty string
instead of a null string (safer as it ensures we do not do arithmetic
on null strings).
Other things:
- Changed struct st_position to an OBJECT and added an initialization
function to it to ensure that we do not copy or use uninitialized
members. The change to a class was also motived that we used "struct
st_position" and POSITION randomly trough the code which was
confusing.
- Notably big rewrite in sql_acl.cc to avoid using deleted objects.
- Changed in sql_partition to use '^' instead of '-'. This is safe as
the operator is either 0 or 0x8000000000000000ULL.
- Added check for select_nr < INT_MAX in JOIN::build_explain() to
avoid bug when get_select() could return NULL.
- Reordered elements in POSITION for better alignment.
- Changed sql_test.cc::print_plan() to use pointers instead of objects.
- Fixed bug in find_set() where could could execute '1 << -1'.
- Added variable have_sanitizer, used by mtr. (This variable was before
only in 10.5 and up). It can now have one of two values:
ASAN or UBSAN.
- Moved ~Archive_share() from ha_archive.cc to ha_archive.h and marked
it virtual. This was an effort to get UBSAN to work with loaded storage
engines. I kept the change as the new place is better.
- Added in CONNECT engine COLBLK::SetName(), to get around a wrong cast
in tabutil.cpp.
- Added HAVE_REPLICATION around usage of rgi_slave, to get embedded
server to compile with UBSAN. (Patch from Marko).
- Added #ifdef for powerpc64 to avoid a bug in old gcc versions related
to integer arithmetic.
Changes that should not be needed but had to be done to suppress warnings
from UBSAN:
- Added static_cast<<uint16_t>> around shift to get rid of a LOT of
compiler warnings when using UBSAN.
- Had to change some '/' of 2 base integers to shift to get rid of
some compile time warnings.
Reviewed by:
- Json changes: Alexey Botchkov
- Charset changes in ctype-uca.c: Alexander Barkov
- InnoDB changes & Embedded server: Marko Mäkelä
- sql_acl.cc changes: Vicențiu Ciorbaru
- build_explain() changes: Sergey Petrunia
2021-04-18 14:29:13 +02:00
|
|
|
if (*err_len == 0)
|
|
|
|
{
|
|
|
|
// report the first error with length > 0
|
|
|
|
*err_pos= (char*) start;
|
|
|
|
*err_len= var_len;
|
|
|
|
*set_warning= 1;
|
|
|
|
}
|
2003-11-03 13:01:59 +01:00
|
|
|
}
|
Fix all warnings given by UBSAN
The easiest way to compile and test the server with UBSAN is to run:
./BUILD/compile-pentium64-ubsan
and then run mysql-test-run.
After this commit, one should be able to run this without any UBSAN
warnings. There is still a few compiler warnings that should be fixed
at some point, but these do not expose any real bugs.
The 'special' cases where we disable, suppress or circumvent UBSAN are:
- ref10 source (as here we intentionally do some shifts that UBSAN
complains about.
- x86 version of optimized int#korr() methods. UBSAN do not like unaligned
memory access of integers. Fixed by using byte_order_generic.h when
compiling with UBSAN
- We use smaller thread stack with ASAN and UBSAN, which forced me to
disable a few tests that prints the thread stack size.
- Verifying class types does not work for shared libraries. I added
suppression in mysql-test-run.pl for this case.
- Added '#ifdef WITH_UBSAN' when using integer arithmetic where it is
safe to have overflows (two cases, in item_func.cc).
Things fixed:
- Don't left shift signed values
(byte_order_generic.h, mysqltest.c, item_sum.cc and many more)
- Don't assign not non existing values to enum variables.
- Ensure that bool and enum values are properly initialized in
constructors. This was needed as UBSAN checks that these types has
correct values when one copies an object.
(gcalc_tools.h, ha_partition.cc, item_sum.cc, partition_element.h ...)
- Ensure we do not called handler functions on unallocated objects or
deleted objects.
(events.cc, sql_acl.cc).
- Fixed bugs in Item_sp::Item_sp() where we did not call constructor
on Query_arena object.
- Fixed several cast of objects to an incompatible class!
(Item.cc, Item_buff.cc, item_timefunc.cc, opt_subselect.cc, sql_acl.cc,
sql_select.cc ...)
- Ensure we do not do integer arithmetic that causes over or underflows.
This includes also ++ and -- of integers.
(Item_func.cc, Item_strfunc.cc, item_timefunc.cc, sql_base.cc ...)
- Added JSON_VALUE_UNITIALIZED to json_value_types and ensure that
value_type is initialized to this instead of to -1, which is not a valid
enum value for json_value_types.
- Ensure we do not call memcpy() when second argument could be null.
- Fixed that Item_func_str::make_empty_result() creates an empty string
instead of a null string (safer as it ensures we do not do arithmetic
on null strings).
Other things:
- Changed struct st_position to an OBJECT and added an initialization
function to it to ensure that we do not copy or use uninitialized
members. The change to a class was also motived that we used "struct
st_position" and POSITION randomly trough the code which was
confusing.
- Notably big rewrite in sql_acl.cc to avoid using deleted objects.
- Changed in sql_partition to use '^' instead of '-'. This is safe as
the operator is either 0 or 0x8000000000000000ULL.
- Added check for select_nr < INT_MAX in JOIN::build_explain() to
avoid bug when get_select() could return NULL.
- Reordered elements in POSITION for better alignment.
- Changed sql_test.cc::print_plan() to use pointers instead of objects.
- Fixed bug in find_set() where could could execute '1 << -1'.
- Added variable have_sanitizer, used by mtr. (This variable was before
only in 10.5 and up). It can now have one of two values:
ASAN or UBSAN.
- Moved ~Archive_share() from ha_archive.cc to ha_archive.h and marked
it virtual. This was an effort to get UBSAN to work with loaded storage
engines. I kept the change as the new place is better.
- Added in CONNECT engine COLBLK::SetName(), to get around a wrong cast
in tabutil.cpp.
- Added HAVE_REPLICATION around usage of rgi_slave, to get embedded
server to compile with UBSAN. (Patch from Marko).
- Added #ifdef for powerpc64 to avoid a bug in old gcc versions related
to integer arithmetic.
Changes that should not be needed but had to be done to suppress warnings
from UBSAN:
- Added static_cast<<uint16_t>> around shift to get rid of a LOT of
compiler warnings when using UBSAN.
- Had to change some '/' of 2 base integers to shift to get rid of
some compile time warnings.
Reviewed by:
- Json changes: Alexey Botchkov
- Charset changes in ctype-uca.c: Alexander Barkov
- InnoDB changes & Embedded server: Marko Mäkelä
- sql_acl.cc changes: Vicențiu Ciorbaru
- build_explain() changes: Sergey Petrunia
2021-04-18 14:29:13 +02:00
|
|
|
else if (find <= sizeof(longlong) * 8)
|
2012-12-21 09:53:42 +01:00
|
|
|
found|= 1ULL << (find - 1);
|
2004-12-06 17:45:32 +01:00
|
|
|
if (pos >= end)
|
2003-11-03 13:01:59 +01:00
|
|
|
break;
|
2004-12-06 17:45:32 +01:00
|
|
|
start= pos + mblen;
|
2003-11-03 13:01:59 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return found;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
Function to find a string in a TYPELIB
|
Fix for BUG#59894
"set optimizer_switch to e or d causes invalid memory writes/valgrind warnings":
due to prefix support, the argument "e" was overwritten with its full value
"engine_condition_pushdown", which caused a buffer overrun.
This was wrong usage of find_type(); other wrong usages are fixed here too.
Please start reading with the comment of typelib.c.
client/mysqldump.c:
A bug: find_type() expects a bitmap as 3rd argument
(each bit is a flag controlling a behaviour of the function);
here it was instead passed the length of the string to search!
That could give random behaviour of find_type()
depending on the string.
We rather need to pass a correct flag to find_type().
The correct flag is FIND_TYPE_BASIC (0).
Flag 8 is not needed as buff cannot have a comma (see how buff is filled).
Flag 1 looks like a superfluous restriction.
Flag 4 is not user-friendly (why use
--compatible=2 rather than --compatible=mysql40 ?, and
we probably not commit to "2" always meaning "mysql40"
until the end of times).
include/mysql.h.pp:
This isn't a problematic API change as we go from char* to const char*:
existing code will run unchanged.
include/typelib.h:
named constants. Not an enum to not significantly change
the declaration of find_type() which would be an API change
(typelib.h is included in mysql.h).
mysql-test/r/mysqldump.result:
correct result (see the two requested modes in SQL_MODE)
mysql-test/suite/sys_vars/t/optimizer_switch_basic.test:
test for BUG#59894. The second SET used to crash.
mysql-test/t/mysqldump.test:
we had no test for multiple modes in --compatible, which is
supported according to --help
mysys/typelib.c:
Fix for BUG#59894. parse_name() is asked to match "e" with a row
of the TYPELIB (the TYPELIB lists permitted flags of optimizer_switch;
and comes from optimizer_switch_names[] of sys_vars.cc).
find_type() is capable of supporting prefixes, but if it is not
passed flag 2 in third argument, it will overwrite its first
argument (the string to search for) with the complete name,
here overwriting "e" with "engine_condition_pushdown". But
as this "e" was a buffer allocated in an Item, it was not big
enough to host the longer name, thus the crash.
We don't need to know the complete flag's name; the output used
from find_type() is just the flag's number (== function's return
code). So we can pass flag 2 to find_type() in parse_name().
After doing this fix and the other fixes in this patch, all usages
of find_type() were using flag 2; in most usages the string to search for,
is not guaranteed to be long enough to host the complete name
(it is either directly from argv, or from alloc_root/my_malloc
done in an earlier call).
Thus, flag 2 is here made implicit: callers need not pass it anymore,
it is always automatically turned on.
This allows to eliminate an oddity: parse_name() took a const char**,
and then removed "const" before calling find_type(), which could
theoretically modify the pointed data, thus lying on constness.
Last, constants for find_type() are now named.
sql-common/client.c:
Two bugs:
1) The enum was not in sync with the array (due to a bad porting of WL 1054;
the extra OPT_ values are about options present in 5.1 and deleted in 5.5);
added a compile_time_assert() to make sure this doesn't happen again
2) find_type() was writing past the end of opt_arg; as opt_arg was allocated
with alloc_root() with no extra space, this was an overrun; it could be seen
when
** building with -DWITH_VALGRIND -DHAVE_purify -DEXTRA_DEBUG
** making execution go through the faulty code; this faulty
code is executed only if the client asks to read a configuration
file like this:
mysql_options(mysql, MYSQL_READ_DEFAULT_FILE, "/tmp/cnf.cnf");
so by adding such line to the start of mysql_client_test.c::client_connect(),
we could see the valgrind warning:
==30548== Invalid write of size 1
==30548== at 0x4C2624C: strcpy (mc_replace_strmem.c:303)
==30548== by 0x48DC29: find_type (typelib.c:120)
==30548== by 0x465686: mysql_read_default_options (client.c:1344)
==30548== by 0x46830F: mysql_real_connect (client.c:2971)
==30548== by 0x409339: client_connect (mysql_client_test.c:331)
==30548== by 0x463A7F: main (mysql_client_test.c:19902)
==30548== Address 0x61875ad is 0 bytes after a block of size 29 alloc'd
==30548== at 0x4C25153: malloc (vg_replace_malloc.c:195)
==30548== by 0x49BFF1: my_malloc (my_malloc.c:38)
==30548== by 0x49C65C: alloc_root (my_alloc.c:166)
==30548== by 0x48EF97: handle_default_option (default.c:381)
==30548== by 0x49068C: search_default_file_with_ext (default.c:992)
==30548== by 0x48F929: search_default_file (default.c:670)
==30548== by 0x48EDC4: my_search_option_files (default.c:312)
==30548== by 0x48F4B1: my_load_defaults (default.c:576)
==30548== by 0x46517A: mysql_read_default_options (client.c:1207)
==30548== by 0x46830F: mysql_real_connect (client.c:2971)
==30548== by 0x409339: client_connect (mysql_client_test.c:331)
==30548== by 0x463A7F: main (mysql_client_test.c:19902)
This is fixed by having find_type() not overwrite anymore.
sql/sql_help.cc:
cast not needed anymore.
sql/table.cc:
cast not needed anymore.
2011-02-11 15:00:09 +01:00
|
|
|
(similar to find_type() of mysys/typelib.c)
|
2003-11-03 13:01:59 +01:00
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
find_type()
|
|
|
|
lib TYPELIB (struct of pointer to values + count)
|
|
|
|
find String to find
|
|
|
|
length Length of string to find
|
|
|
|
part_match Allow part matching of value
|
|
|
|
|
|
|
|
RETURN
|
|
|
|
0 error
|
|
|
|
> 0 position in TYPELIB->type_names +1
|
|
|
|
*/
|
|
|
|
|
2018-02-06 13:55:58 +01:00
|
|
|
uint find_type(const TYPELIB *lib, const char *find, size_t length,
|
2007-03-27 18:27:58 +02:00
|
|
|
bool part_match)
|
2003-11-03 13:01:59 +01:00
|
|
|
{
|
|
|
|
uint found_count=0, found_pos=0;
|
|
|
|
const char *end= find+length;
|
|
|
|
const char *i;
|
|
|
|
const char *j;
|
|
|
|
for (uint pos=0 ; (j=lib->type_names[pos++]) ; )
|
|
|
|
{
|
|
|
|
for (i=find ; i != end &&
|
|
|
|
my_toupper(system_charset_info,*i) ==
|
|
|
|
my_toupper(system_charset_info,*j) ; i++, j++) ;
|
|
|
|
if (i == end)
|
|
|
|
{
|
|
|
|
if (! *j)
|
|
|
|
return(pos);
|
|
|
|
found_count++;
|
|
|
|
found_pos= pos;
|
|
|
|
}
|
|
|
|
}
|
2003-11-20 21:06:25 +01:00
|
|
|
return(found_count == 1 && part_match ? found_pos : 0);
|
2003-11-03 13:01:59 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-10-25 14:51:26 +02:00
|
|
|
/*
|
|
|
|
Find a string in a list of strings according to collation
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
find_type2()
|
|
|
|
lib TYPELIB (struct of pointer to values + count)
|
|
|
|
x String to find
|
|
|
|
length String length
|
|
|
|
cs Character set + collation to use for comparison
|
|
|
|
|
|
|
|
NOTES
|
|
|
|
|
|
|
|
RETURN
|
|
|
|
0 No matching value
|
|
|
|
>0 Offset+1 in typelib for matched string
|
|
|
|
*/
|
|
|
|
|
2018-02-06 13:55:58 +01:00
|
|
|
uint find_type2(const TYPELIB *typelib, const char *x, size_t length,
|
2007-03-27 18:27:58 +02:00
|
|
|
CHARSET_INFO *cs)
|
2004-10-25 14:51:26 +02:00
|
|
|
{
|
2005-02-25 15:53:22 +01:00
|
|
|
int pos;
|
2004-10-25 14:51:26 +02:00
|
|
|
const char *j;
|
|
|
|
DBUG_ENTER("find_type2");
|
2018-02-06 14:22:15 +01:00
|
|
|
DBUG_PRINT("enter",("x: '%.*s' lib: %p", (int)length, x, typelib));
|
2004-10-25 14:51:26 +02:00
|
|
|
|
|
|
|
if (!typelib->count)
|
|
|
|
{
|
|
|
|
DBUG_PRINT("exit",("no count"));
|
|
|
|
DBUG_RETURN(0);
|
|
|
|
}
|
2005-01-11 15:38:03 +01:00
|
|
|
|
2005-02-25 15:53:22 +01:00
|
|
|
for (pos=0 ; (j=typelib->type_names[pos]) ; pos++)
|
2004-10-25 14:51:26 +02:00
|
|
|
{
|
2020-01-26 17:27:13 +01:00
|
|
|
if (!cs->strnncoll(x, length,
|
|
|
|
j, typelib->type_lengths[pos]))
|
2004-10-25 14:51:26 +02:00
|
|
|
DBUG_RETURN(pos+1);
|
|
|
|
}
|
|
|
|
DBUG_PRINT("exit",("Couldn't find type"));
|
|
|
|
DBUG_RETURN(0);
|
|
|
|
} /* find_type */
|
|
|
|
|
|
|
|
|
2004-12-21 14:12:27 +01:00
|
|
|
/*
|
|
|
|
Un-hex all elements in a typelib
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
unhex_type2()
|
|
|
|
interval TYPELIB (struct of pointer to values + lengths + count)
|
|
|
|
|
|
|
|
NOTES
|
|
|
|
|
|
|
|
RETURN
|
|
|
|
N/A
|
|
|
|
*/
|
|
|
|
|
|
|
|
void unhex_type2(TYPELIB *interval)
|
|
|
|
{
|
|
|
|
for (uint pos= 0; pos < interval->count; pos++)
|
|
|
|
{
|
|
|
|
char *from, *to;
|
|
|
|
for (from= to= (char*) interval->type_names[pos]; *from; )
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
Note, hexchar_to_int(*from++) doesn't work
|
|
|
|
one some compilers, e.g. IRIX. Looks like a compiler
|
|
|
|
bug in inline functions in combination with arguments
|
|
|
|
that have a side effect. So, let's use from[0] and from[1]
|
|
|
|
and increment 'from' by two later.
|
|
|
|
*/
|
|
|
|
|
|
|
|
*to++= (char) (hexchar_to_int(from[0]) << 4) +
|
|
|
|
hexchar_to_int(from[1]);
|
|
|
|
from+= 2;
|
|
|
|
}
|
|
|
|
interval->type_lengths[pos] /= 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-11-03 13:01:59 +01:00
|
|
|
/*
|
|
|
|
Check if the first word in a string is one of the ones in TYPELIB
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
check_word()
|
|
|
|
lib TYPELIB
|
|
|
|
val String to check
|
|
|
|
end End of input
|
|
|
|
end_of_word Store value of last used byte here if we found word
|
|
|
|
|
|
|
|
RETURN
|
|
|
|
0 No matching value
|
|
|
|
> 1 lib->type_names[#-1] matched
|
|
|
|
end_of_word will point to separator character/end in 'val'
|
|
|
|
*/
|
|
|
|
|
|
|
|
uint check_word(TYPELIB *lib, const char *val, const char *end,
|
|
|
|
const char **end_of_word)
|
|
|
|
{
|
|
|
|
int res;
|
|
|
|
const char *ptr;
|
|
|
|
|
|
|
|
/* Fiend end of word */
|
|
|
|
for (ptr= val ; ptr < end && my_isalpha(&my_charset_latin1, *ptr) ; ptr++)
|
|
|
|
;
|
|
|
|
if ((res=find_type(lib, val, (uint) (ptr - val), 1)) > 0)
|
|
|
|
*end_of_word= ptr;
|
|
|
|
return res;
|
|
|
|
}
|
2005-12-31 06:01:26 +01:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Converts a string between character sets
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
strconvert()
|
|
|
|
from_cs source character set
|
|
|
|
from source, a null terminated string
|
|
|
|
to destination buffer
|
|
|
|
to_length destination buffer length
|
|
|
|
|
|
|
|
NOTES
|
|
|
|
'to' is always terminated with a '\0' character.
|
|
|
|
If there is no enough space to convert whole string,
|
|
|
|
only prefix is converted, and terminated with '\0'.
|
|
|
|
|
|
|
|
RETURN VALUES
|
|
|
|
result string length
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
2018-02-06 13:55:58 +01:00
|
|
|
uint strconvert(CHARSET_INFO *from_cs, const char *from, size_t from_length,
|
|
|
|
CHARSET_INFO *to_cs, char *to, size_t to_length, uint *errors)
|
2005-12-31 06:01:26 +01:00
|
|
|
{
|
|
|
|
int cnvres;
|
|
|
|
my_wc_t wc;
|
|
|
|
char *to_start= to;
|
|
|
|
uchar *to_end= (uchar*) to + to_length - 1;
|
2013-07-03 21:50:34 +02:00
|
|
|
const uchar *from_end= (const uchar*) from + from_length;
|
2007-08-13 15:11:25 +02:00
|
|
|
my_charset_conv_mb_wc mb_wc= from_cs->cset->mb_wc;
|
|
|
|
my_charset_conv_wc_mb wc_mb= to_cs->cset->wc_mb;
|
2005-12-31 06:01:26 +01:00
|
|
|
uint error_count= 0;
|
|
|
|
|
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
if ((cnvres= (*mb_wc)(from_cs, &wc,
|
2013-07-03 21:50:34 +02:00
|
|
|
(uchar*) from, from_end)) > 0)
|
2005-12-31 06:01:26 +01:00
|
|
|
{
|
|
|
|
if (!wc)
|
|
|
|
break;
|
|
|
|
from+= cnvres;
|
|
|
|
}
|
|
|
|
else if (cnvres == MY_CS_ILSEQ)
|
|
|
|
{
|
|
|
|
error_count++;
|
|
|
|
from++;
|
|
|
|
wc= '?';
|
|
|
|
}
|
|
|
|
else
|
|
|
|
break; // Impossible char.
|
|
|
|
|
|
|
|
outp:
|
|
|
|
|
|
|
|
if ((cnvres= (*wc_mb)(to_cs, wc, (uchar*) to, to_end)) > 0)
|
|
|
|
to+= cnvres;
|
|
|
|
else if (cnvres == MY_CS_ILUNI && wc != '?')
|
|
|
|
{
|
|
|
|
error_count++;
|
|
|
|
wc= '?';
|
|
|
|
goto outp;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
*to= '\0';
|
2005-12-31 09:34:39 +01:00
|
|
|
*errors= error_count;
|
2005-12-31 06:01:26 +01:00
|
|
|
return (uint32) (to - to_start);
|
|
|
|
|
|
|
|
}
|
2006-10-10 17:59:46 +02:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
Searches for a LEX_STRING in an LEX_STRING array.
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
find_string_in_array()
|
|
|
|
heap The array
|
|
|
|
needle The string to search for
|
|
|
|
|
|
|
|
NOTE
|
|
|
|
The last LEX_STRING in the array should have str member set to NULL
|
|
|
|
|
|
|
|
RETURN VALUES
|
|
|
|
-1 Not found
|
|
|
|
>=0 Ordinal position
|
|
|
|
*/
|
|
|
|
|
2017-04-23 18:39:57 +02:00
|
|
|
int find_string_in_array(LEX_CSTRING * const haystack, LEX_CSTRING * const needle,
|
2006-10-10 17:59:46 +02:00
|
|
|
CHARSET_INFO * const cs)
|
|
|
|
{
|
2017-04-23 18:39:57 +02:00
|
|
|
const LEX_CSTRING *pos;
|
2006-10-10 17:59:46 +02:00
|
|
|
for (pos= haystack; pos->str; pos++)
|
2020-01-26 17:27:13 +01:00
|
|
|
if (!cs->strnncollsp(pos->str, pos->length,
|
|
|
|
needle->str, needle->length))
|
2006-10-10 17:59:46 +02:00
|
|
|
{
|
2017-10-09 21:53:27 +02:00
|
|
|
return (int)(pos - haystack);
|
2006-10-10 17:59:46 +02:00
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
2009-12-22 10:35:56 +01:00
|
|
|
|
|
|
|
|
2017-04-23 18:39:57 +02:00
|
|
|
const char *set_to_string(THD *thd, LEX_CSTRING *result, ulonglong set,
|
|
|
|
const char *lib[])
|
2009-12-22 10:35:56 +01:00
|
|
|
{
|
|
|
|
char buff[STRING_BUFFER_USUAL_SIZE*8];
|
|
|
|
String tmp(buff, sizeof(buff), &my_charset_latin1);
|
2017-04-23 18:39:57 +02:00
|
|
|
LEX_CSTRING unused;
|
2009-12-22 10:35:56 +01:00
|
|
|
|
|
|
|
if (!result)
|
|
|
|
result= &unused;
|
|
|
|
|
|
|
|
tmp.length(0);
|
|
|
|
|
|
|
|
for (uint i= 0; set; i++, set >>= 1)
|
|
|
|
if (set & 1) {
|
|
|
|
tmp.append(lib[i]);
|
|
|
|
tmp.append(',');
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tmp.length())
|
|
|
|
{
|
|
|
|
result->str= thd->strmake(tmp.ptr(), tmp.length()-1);
|
|
|
|
result->length= tmp.length()-1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
result->str= const_cast<char*>("");
|
|
|
|
result->length= 0;
|
|
|
|
}
|
|
|
|
return result->str;
|
|
|
|
}
|
|
|
|
|
2017-04-23 18:39:57 +02:00
|
|
|
const char *flagset_to_string(THD *thd, LEX_CSTRING *result, ulonglong set,
|
|
|
|
const char *lib[])
|
2009-12-22 10:35:56 +01:00
|
|
|
{
|
|
|
|
char buff[STRING_BUFFER_USUAL_SIZE*8];
|
|
|
|
String tmp(buff, sizeof(buff), &my_charset_latin1);
|
2017-04-23 18:39:57 +02:00
|
|
|
LEX_CSTRING unused;
|
2009-12-22 10:35:56 +01:00
|
|
|
|
|
|
|
if (!result) result= &unused;
|
|
|
|
|
|
|
|
tmp.length(0);
|
|
|
|
|
|
|
|
// note that the last element is always "default", and it's ignored below
|
|
|
|
for (uint i= 0; lib[i+1]; i++, set >>= 1)
|
|
|
|
{
|
|
|
|
tmp.append(lib[i]);
|
|
|
|
tmp.append(set & 1 ? "=on," : "=off,");
|
|
|
|
}
|
|
|
|
|
|
|
|
result->str= thd->strmake(tmp.ptr(), tmp.length()-1);
|
|
|
|
result->length= tmp.length()-1;
|
|
|
|
|
|
|
|
return result->str;
|
|
|
|
}
|