mirror of
https://github.com/MariaDB/server.git
synced 2026-10-23 18:49:29 +03:00
Add detection of partial matches for strnncoll
This is achived by changing the 'is_prefix' parameter to strncoll from a my_bool to my_bool*. This parameter is null if not specified by the caller. If the is_prefix parameter is set to point to a my_bool variable, this variable will be set to 1 if the second argument is a prefix of the first. This is needed by TO_DATE to be able to detect partial uniqiue matches of months etc. find_type() did this for latin1 strings, but we did not do this for utf8mb4 strings. This patch fixes this incompatibility.
This commit is contained in:
@@ -557,7 +557,7 @@ struct my_collation_handler_st
|
||||
my_bool (*init)(struct charset_info_st *, MY_CHARSET_LOADER *);
|
||||
/* Collation routines */
|
||||
int (*strnncoll)(CHARSET_INFO *,
|
||||
const uchar *, size_t, const uchar *, size_t, my_bool);
|
||||
const uchar *, size_t, const uchar *, size_t, my_bool*);
|
||||
int (*strnncollsp)(CHARSET_INFO *,
|
||||
const uchar *, size_t, const uchar *, size_t);
|
||||
/*
|
||||
@@ -716,6 +716,7 @@ struct my_charset_handler_st
|
||||
size_t (*numchars)(CHARSET_INFO *, const char *b, const char *e);
|
||||
size_t (*charpos)(CHARSET_INFO *, const char *b, const char *e,
|
||||
size_t pos);
|
||||
/* Length without trailing space */
|
||||
size_t (*lengthsp)(CHARSET_INFO *, const char *ptr, size_t length);
|
||||
size_t (*numcells)(CHARSET_INFO *, const char *b, const char *e);
|
||||
|
||||
@@ -1146,22 +1147,23 @@ struct charset_info_st
|
||||
}
|
||||
|
||||
int strnncoll(const LEX_CSTRING a, const LEX_CSTRING b,
|
||||
my_bool b_is_prefix= FALSE) const
|
||||
my_bool *b_is_prefix= 0) const
|
||||
{
|
||||
DBUG_ASSERT(is_valid_string(a));
|
||||
DBUG_ASSERT(is_valid_string(b));
|
||||
return (coll->strnncoll)(this,
|
||||
(const uchar *) a.str, a.length,
|
||||
(const uchar *) b.str, b.length, b_is_prefix);
|
||||
(const uchar *) b.str, b.length,
|
||||
b_is_prefix);
|
||||
}
|
||||
|
||||
int strnncoll(const uchar *a, size_t alen,
|
||||
const uchar *b, size_t blen, my_bool b_is_prefix= FALSE) const
|
||||
const uchar *b, size_t blen, my_bool *b_is_prefix= 0) const
|
||||
{
|
||||
return (coll->strnncoll)(this, a, alen, b, blen, b_is_prefix);
|
||||
}
|
||||
int strnncoll(const char *a, size_t alen,
|
||||
const char *b, size_t blen, my_bool b_is_prefix= FALSE) const
|
||||
const char *b, size_t blen, my_bool *b_is_prefix= 0) const
|
||||
{
|
||||
return (coll->strnncoll)(this,
|
||||
(const uchar *) a, alen,
|
||||
@@ -1478,7 +1480,7 @@ static inline int
|
||||
my_ci_strnncoll(CHARSET_INFO *ci,
|
||||
const uchar *a, size_t alen,
|
||||
const uchar *b, size_t blen,
|
||||
my_bool b_is_prefix)
|
||||
my_bool *b_is_prefix)
|
||||
{
|
||||
return (ci->coll->strnncoll)(ci, a, alen, b, blen, b_is_prefix);
|
||||
}
|
||||
@@ -1635,7 +1637,7 @@ const uint16 *my_cs_contraction2_weight(CHARSET_INFO *cs, my_wc_t wc1,
|
||||
|
||||
/* declarations for simple charsets */
|
||||
extern int my_strnncoll_simple(CHARSET_INFO *, const uchar *, size_t,
|
||||
const uchar *, size_t, my_bool);
|
||||
const uchar *, size_t, my_bool*);
|
||||
|
||||
extern int my_strnncollsp_simple(CHARSET_INFO *, const uchar *, size_t,
|
||||
const uchar *, size_t);
|
||||
|
||||
@@ -140,7 +140,7 @@ static inline int ha_compare_char_varying(CHARSET_INFO *charset_info,
|
||||
b, b_length);
|
||||
return charset_info->coll->strnncoll(charset_info,
|
||||
a, a_length,
|
||||
b, b_length, TRUE/*prefix*/);
|
||||
b, b_length, &b_is_prefix);
|
||||
}
|
||||
|
||||
|
||||
@@ -190,7 +190,7 @@ static inline int ha_compare_char_fixed(CHARSET_INFO *charset_info,
|
||||
MY_STRNNCOLLSP_NCHARS_EMULATE_TRIMMED_TRAILING_SPACES);
|
||||
return charset_info->coll->strnncoll(charset_info,
|
||||
a, a_length,
|
||||
b, b_length, TRUE/*prefix*/);
|
||||
b, b_length, &b_is_prefix);
|
||||
}
|
||||
|
||||
|
||||
@@ -218,10 +218,11 @@ static inline int ha_compare_word_prefix(CHARSET_INFO *charset_info,
|
||||
const uchar *a, size_t a_length,
|
||||
const uchar *b, size_t b_length)
|
||||
{
|
||||
my_bool b_is_prefix;
|
||||
return charset_info->coll->strnncoll(charset_info,
|
||||
a, a_length,
|
||||
b, b_length,
|
||||
TRUE/*b_is_prefix*/);
|
||||
&b_is_prefix);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -618,5 +618,10 @@ Warnings:
|
||||
Note 1003 select `test`.`t1`.`c1` AS `c1` from `test`.`t1` where concat(`test`.`t1`.`c1`) = 'ä' and concat(`test`.`t1`.`c1`) like 'ae'
|
||||
DROP TABLE IF EXISTS t1;
|
||||
#
|
||||
# MDEV-38608 TO_DATE: Server crash in my_uca_strnncoll_multilevel_generic
|
||||
#
|
||||
CREATE TABLE t1 (f ENUM('foo','bar')) COLLATE uca1400_ai_cs;
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# End of 10.0 tests
|
||||
#
|
||||
|
||||
@@ -47,6 +47,13 @@ SET NAMES utf8mb4 COLLATE uca1400_ai_ci;
|
||||
--source include/ctype_like_cond_propagation.inc
|
||||
--source include/ctype_like_cond_propagation_utf8_german.inc
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-38608 TO_DATE: Server crash in my_uca_strnncoll_multilevel_generic
|
||||
--echo #
|
||||
|
||||
CREATE TABLE t1 (f ENUM('foo','bar')) COLLATE uca1400_ai_cs;
|
||||
DROP TABLE t1;
|
||||
|
||||
--echo #
|
||||
--echo # End of 10.0 tests
|
||||
--echo #
|
||||
|
||||
@@ -9441,10 +9441,11 @@ bool is_secure_file_path(char *path)
|
||||
}
|
||||
else
|
||||
{
|
||||
my_bool use_prefix;
|
||||
if (files_charset_info->strnncoll(buff2, strlen(buff2),
|
||||
opt_secure_file_priv,
|
||||
opt_secure_file_priv_len,
|
||||
TRUE))
|
||||
&use_prefix))
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
|
||||
@@ -2383,6 +2383,7 @@ static bool is_mysql_datadir_path(const char *path)
|
||||
convert_dirname(mysql_data_dir, mysql_unpacked_real_data_home, NullS);
|
||||
size_t mysql_data_home_len= dirname_length(mysql_data_dir);
|
||||
size_t path_len = dirname_length(path_dir);
|
||||
my_bool part_matched;
|
||||
|
||||
if (path_len < mysql_data_home_len)
|
||||
return true;
|
||||
@@ -2393,7 +2394,7 @@ static bool is_mysql_datadir_path(const char *path)
|
||||
return(files_charset_info->strnncoll((uchar *) path_dir, path_len,
|
||||
(uchar *) mysql_data_dir,
|
||||
mysql_data_home_len,
|
||||
TRUE));
|
||||
&part_matched));
|
||||
}
|
||||
|
||||
/*********************************************************************//**
|
||||
|
||||
@@ -258,9 +258,10 @@ inline bool cmp_dfield_dfield_eq_prefix(const dfield_t *dfield1,
|
||||
|
||||
uint cs_num= dtype_get_charset_coll(type->prtype);
|
||||
CHARSET_INFO *cs= get_charset(cs_num, MYF(MY_WME));
|
||||
my_bool use_prefix;
|
||||
ut_a(cs);
|
||||
return !cs->strnncoll(static_cast<const uchar*>(dfield_get_data(dfield1)),
|
||||
dfield_get_len(dfield1),
|
||||
static_cast<const uchar*>(dfield_get_data(dfield2)),
|
||||
dfield_get_len(dfield2), 1);
|
||||
dfield_get_len(dfield2), &use_prefix);
|
||||
}
|
||||
|
||||
@@ -259,6 +259,11 @@ Simple scanner routines
|
||||
-----------------------
|
||||
scan() - to skip leading spaces in the given string.
|
||||
Used when a string value is inserted into a numeric field.
|
||||
the last parameter is one of:
|
||||
|
||||
MY_SEQ_INTTAIL ; Ignore '.' and a set of '0'
|
||||
MY_SEQ_SPACES ; Skip over pre-space
|
||||
MY_SEQ_NOSPACES; ; Skip over non space characters
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -83,11 +83,23 @@ my_coll_init_8bit_bin(struct charset_info_st *cs,
|
||||
static int my_strnncoll_binary(CHARSET_INFO * cs __attribute__((unused)),
|
||||
const uchar *s, size_t slen,
|
||||
const uchar *t, size_t tlen,
|
||||
my_bool t_is_prefix)
|
||||
my_bool *t_is_prefix)
|
||||
{
|
||||
size_t len=MY_MIN(slen,tlen);
|
||||
size_t len= MY_MIN(slen,tlen);
|
||||
int cmp= len ? memcmp(s, t, len) : 0;
|
||||
return cmp ? cmp : (int)((t_is_prefix ? len : slen) - tlen);
|
||||
|
||||
if (!t_is_prefix)
|
||||
{
|
||||
if (cmp)
|
||||
return cmp;
|
||||
return (int) (slen - tlen);
|
||||
}
|
||||
if (cmp)
|
||||
{
|
||||
*t_is_prefix= 0;
|
||||
return cmp;
|
||||
}
|
||||
return !(*t_is_prefix= tlen <= slen);
|
||||
}
|
||||
|
||||
|
||||
@@ -144,11 +156,23 @@ static int my_strnncollsp_nchars_binary(CHARSET_INFO * cs __attribute__((unused)
|
||||
static int my_strnncoll_8bit_bin(CHARSET_INFO * cs __attribute__((unused)),
|
||||
const uchar *s, size_t slen,
|
||||
const uchar *t, size_t tlen,
|
||||
my_bool t_is_prefix)
|
||||
my_bool *t_is_prefix)
|
||||
{
|
||||
size_t len=MY_MIN(slen,tlen);
|
||||
size_t len= MY_MIN(slen,tlen);
|
||||
int cmp= len ? memcmp(s, t, len) : 0;
|
||||
return cmp ? cmp : (int)((t_is_prefix ? len : slen) - tlen);
|
||||
|
||||
if (!t_is_prefix)
|
||||
{
|
||||
if (cmp)
|
||||
return cmp;
|
||||
return (int) (slen - tlen);
|
||||
}
|
||||
if (cmp)
|
||||
{
|
||||
*t_is_prefix= 0;
|
||||
return cmp;
|
||||
}
|
||||
return !(*t_is_prefix= tlen <= slen);
|
||||
}
|
||||
|
||||
|
||||
@@ -232,7 +256,7 @@ static int my_strnncollsp_8bit_nopad_bin(CHARSET_INFO * cs
|
||||
const uchar *a, size_t a_length,
|
||||
const uchar *b, size_t b_length)
|
||||
{
|
||||
return my_strnncoll_8bit_bin(cs, a, a_length, b, b_length, FALSE);
|
||||
return my_strnncoll_8bit_bin(cs, a, a_length, b, b_length, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -218,14 +218,20 @@ while (1) \
|
||||
static int my_strnncoll_czech(CHARSET_INFO *cs __attribute__((unused)),
|
||||
const uchar *s1, size_t len1,
|
||||
const uchar *s2, size_t len2,
|
||||
my_bool s2_is_prefix)
|
||||
my_bool *s2_is_prefix)
|
||||
{
|
||||
int v1, v2;
|
||||
const uchar *p1, * p2, * store1, * store2;
|
||||
int pass1 = 0, pass2 = 0;
|
||||
|
||||
if (s2_is_prefix && len1 > len2)
|
||||
len1=len2;
|
||||
if (s2_is_prefix)
|
||||
{
|
||||
*s2_is_prefix= 0;
|
||||
if (len1 > len2)
|
||||
{
|
||||
*s2_is_prefix= 1;
|
||||
len1= len2;
|
||||
}
|
||||
}
|
||||
|
||||
p1 = s1; p2 = s2;
|
||||
store1 = s1; store2 = s2;
|
||||
@@ -236,7 +242,11 @@ static int my_strnncoll_czech(CHARSET_INFO *cs __attribute__((unused)),
|
||||
NEXT_CMP_VALUE(s1, p1, store1, pass1, v1, (int)len1);
|
||||
NEXT_CMP_VALUE(s2, p2, store2, pass2, v2, (int)len2);
|
||||
if ((diff = v1 - v2))
|
||||
{
|
||||
if (s2_is_prefix)
|
||||
*s2_is_prefix= 0;
|
||||
return diff;
|
||||
}
|
||||
}
|
||||
while (v1);
|
||||
return 0;
|
||||
|
||||
@@ -589,11 +589,13 @@ static const uchar combo2map[]={
|
||||
static int my_strnncoll_latin1_de(CHARSET_INFO *cs __attribute__((unused)),
|
||||
const uchar *a, size_t a_length,
|
||||
const uchar *b, size_t b_length,
|
||||
my_bool b_is_prefix)
|
||||
my_bool *b_is_prefix)
|
||||
{
|
||||
const uchar *a_end= a + a_length;
|
||||
const uchar *b_end= b + b_length;
|
||||
uchar a_char, a_extend= 0, b_char, b_extend= 0;
|
||||
if (b_is_prefix)
|
||||
*b_is_prefix= 0;
|
||||
|
||||
while ((a < a_end || a_extend) && (b < b_end || b_extend))
|
||||
{
|
||||
@@ -622,7 +624,7 @@ static int my_strnncoll_latin1_de(CHARSET_INFO *cs __attribute__((unused)),
|
||||
A simple test of string lengths won't work -- we test to see
|
||||
which string ran out first
|
||||
*/
|
||||
return ((a < a_end || a_extend) ? (b_is_prefix ? 0 : 1) :
|
||||
return ((a < a_end || a_extend) ? (b_is_prefix ? (*b_is_prefix= 1, 0) : 1) :
|
||||
(b < b_end || b_extend) ? -1 : 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -142,22 +142,40 @@ my_strnxfrm_simple_nopad(CHARSET_INFO * cs,
|
||||
|
||||
int my_strnncoll_simple(CHARSET_INFO * cs, const uchar *s, size_t slen,
|
||||
const uchar *t, size_t tlen,
|
||||
my_bool t_is_prefix)
|
||||
my_bool *t_is_prefix)
|
||||
{
|
||||
size_t len = ( slen > tlen ) ? tlen : slen;
|
||||
const uchar *map= cs->sort_order;
|
||||
if (t_is_prefix && slen > tlen)
|
||||
slen=tlen;
|
||||
my_bool dummy;
|
||||
|
||||
if (t_is_prefix)
|
||||
{
|
||||
*t_is_prefix= 0;
|
||||
if (slen > tlen)
|
||||
{
|
||||
*t_is_prefix= 1;
|
||||
slen= tlen;
|
||||
}
|
||||
}
|
||||
else
|
||||
t_is_prefix= &dummy;
|
||||
|
||||
while (len--)
|
||||
{
|
||||
if (map[*s++] != map[*t++])
|
||||
{
|
||||
*t_is_prefix= 0;
|
||||
return ((int) map[s[-1]] - (int) map[t[-1]]);
|
||||
}
|
||||
}
|
||||
/*
|
||||
We can't use (slen - tlen) here as the result may be outside of the
|
||||
precision of a signed int
|
||||
*/
|
||||
return slen > tlen ? 1 : slen < tlen ? -1 : 0 ;
|
||||
if (tlen == slen)
|
||||
return 0;
|
||||
*t_is_prefix= 0;
|
||||
return slen > tlen ? 1 : -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -516,14 +516,21 @@ static
|
||||
int my_strnncoll_tis620(CHARSET_INFO *cs __attribute__((unused)),
|
||||
const uchar *s1, size_t len1,
|
||||
const uchar *s2, size_t len2,
|
||||
my_bool s2_is_prefix)
|
||||
my_bool *s2_is_prefix)
|
||||
{
|
||||
uchar buf[80] ;
|
||||
uchar *tc1, *tc2;
|
||||
int i;
|
||||
|
||||
if (s2_is_prefix && len1 > len2)
|
||||
len1= len2;
|
||||
if (s2_is_prefix)
|
||||
{
|
||||
*s2_is_prefix= 0;
|
||||
if (len1 > len2)
|
||||
{
|
||||
*s2_is_prefix= 1;
|
||||
len1= len2;
|
||||
}
|
||||
}
|
||||
|
||||
tc1= buf;
|
||||
if ((len1 + len2 +2) > (int) sizeof(buf))
|
||||
@@ -538,6 +545,8 @@ int my_strnncoll_tis620(CHARSET_INFO *cs __attribute__((unused)),
|
||||
i= strcmp((char*)tc1, (char*)tc2);
|
||||
if (tc1 != buf)
|
||||
my_free(tc1);
|
||||
if (i && s2_is_prefix)
|
||||
*s2_is_prefix= 0;
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ MY_FUNCTION_NAME(strnncoll_onelevel)(CHARSET_INFO *cs,
|
||||
const MY_UCA_WEIGHT_LEVEL *level,
|
||||
const uchar *s, size_t slen,
|
||||
const uchar *t, size_t tlen,
|
||||
my_bool t_is_prefix)
|
||||
my_bool *t_is_prefix)
|
||||
{
|
||||
my_uca_scanner sscanner;
|
||||
my_uca_scanner tscanner;
|
||||
@@ -119,7 +119,12 @@ MY_FUNCTION_NAME(strnncoll_onelevel)(CHARSET_INFO *cs,
|
||||
t_res= MY_FUNCTION_NAME(scanner_next)(&tscanner, ¶m);
|
||||
} while ( s_res == t_res && s_res >0);
|
||||
|
||||
return (t_is_prefix && t_res < 0) ? 0 : (s_res - t_res);
|
||||
if (t_is_prefix)
|
||||
{
|
||||
if ((*t_is_prefix= s_res != t_res && t_res < 0))
|
||||
return 0;
|
||||
}
|
||||
return (s_res - t_res);
|
||||
}
|
||||
|
||||
|
||||
@@ -130,7 +135,7 @@ static int
|
||||
MY_FUNCTION_NAME(strnncoll)(CHARSET_INFO *cs,
|
||||
const uchar *s, size_t slen,
|
||||
const uchar *t, size_t tlen,
|
||||
my_bool t_is_prefix)
|
||||
my_bool *t_is_prefix)
|
||||
{
|
||||
return MY_FUNCTION_NAME(strnncoll_onelevel)(cs, &cs->uca->level[0],
|
||||
s, slen, t, tlen, t_is_prefix);
|
||||
@@ -139,14 +144,19 @@ MY_FUNCTION_NAME(strnncoll)(CHARSET_INFO *cs,
|
||||
|
||||
/*
|
||||
Multi-level, PAD SPACE.
|
||||
|
||||
Note that t_is_prefix is set from the last call to strnncoll_onelevel
|
||||
*/
|
||||
static int
|
||||
MY_FUNCTION_NAME(strnncoll_multilevel)(CHARSET_INFO *cs,
|
||||
const uchar *s, size_t slen,
|
||||
const uchar *t, size_t tlen,
|
||||
my_bool t_is_prefix)
|
||||
my_bool *t_is_prefix)
|
||||
{
|
||||
uint i, level_flags= cs->levels_for_order;
|
||||
if (t_is_prefix && *t_is_prefix)
|
||||
*t_is_prefix= 0;
|
||||
|
||||
for (i= 0; level_flags; i++, level_flags>>= 1)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@@ -452,15 +452,22 @@ static const struct wordvalue doubles[] = {
|
||||
static int my_strnncoll_win1250ch(CHARSET_INFO *cs __attribute__((unused)),
|
||||
const uchar *s1, size_t len1,
|
||||
const uchar *s2, size_t len2,
|
||||
my_bool s2_is_prefix)
|
||||
my_bool *s2_is_prefix)
|
||||
{
|
||||
int v1, v2;
|
||||
const uchar *p1, * p2;
|
||||
int pass1 = 0, pass2 = 0;
|
||||
int diff;
|
||||
|
||||
if (s2_is_prefix && len1 > len2)
|
||||
len1=len2;
|
||||
if (s2_is_prefix)
|
||||
{
|
||||
*s2_is_prefix= 0;
|
||||
if (len1 > len2)
|
||||
{
|
||||
*s2_is_prefix= 1;
|
||||
len1= len2;
|
||||
}
|
||||
}
|
||||
|
||||
p1 = s1; p2 = s2;
|
||||
|
||||
@@ -469,7 +476,11 @@ static int my_strnncoll_win1250ch(CHARSET_INFO *cs __attribute__((unused)),
|
||||
NEXT_CMP_VALUE(s1, p1, pass1, v1, (int)len1);
|
||||
NEXT_CMP_VALUE(s2, p2, pass2, v2, (int)len2);
|
||||
if ((diff = v1 - v2))
|
||||
{
|
||||
if (s2_is_prefix)
|
||||
*s2_is_prefix= 0;
|
||||
return diff;
|
||||
}
|
||||
} while (v1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -218,16 +218,19 @@ bad:
|
||||
@param b - the right string
|
||||
@param b_length - the length of the right string
|
||||
@param b_is_prefix - if the caller wants to check if "b" is a prefix of "a"
|
||||
*b_is_prefix is set to 1 if it was a prefix match
|
||||
@return - the comparison result
|
||||
*/
|
||||
static int
|
||||
MY_FUNCTION_NAME(strnncoll)(CHARSET_INFO *cs __attribute__((unused)),
|
||||
const uchar *a, size_t a_length,
|
||||
const uchar *b, size_t b_length,
|
||||
my_bool b_is_prefix)
|
||||
my_bool *b_is_prefix)
|
||||
{
|
||||
const uchar *a_end= a + a_length;
|
||||
const uchar *b_end= b + b_length;
|
||||
if (b_is_prefix)
|
||||
*b_is_prefix= 0;
|
||||
for ( ; ; )
|
||||
{
|
||||
int a_weight, b_weight, res;
|
||||
@@ -271,7 +274,14 @@ MY_FUNCTION_NAME(strnncoll)(CHARSET_INFO *cs __attribute__((unused)),
|
||||
return b_wlen ? -1 : 0;
|
||||
|
||||
if (!b_wlen)
|
||||
return b_is_prefix ? 0 : +1;
|
||||
{
|
||||
if (b_is_prefix)
|
||||
{
|
||||
*b_is_prefix= 1; /* Prefix match */
|
||||
return 0;
|
||||
}
|
||||
return +1;
|
||||
}
|
||||
|
||||
if ((res= (a_weight - b_weight)))
|
||||
return res;
|
||||
|
||||
Reference in New Issue
Block a user