mirror of
https://github.com/MariaDB/server.git
synced 2025-07-18 23:03:28 +03:00
MDEV-28835 Assertion `(length % 4) == 0' failed in my_lengthsp_utf32 on INSERT
Problem: Item_func_date_format::val_str() and make_date_time() did not take into account that the format string and the result string (separately or at the same time) can be of a tricky character set like UCS2, UTF16, UTF32. As a result, DATE_FORMAT() could generate an ill-formed result which crashed on DBUG_ASSERTs testing well-formedness in other parts of the code. Fix: 1. class String changes Removing String::append_with_prefill(). It was not compatible with tricky character sets. Also it was inconvenient to use and required too much duplicate code on the caller side. Adding String::append_zerofill() instead. It's compatible with tricky character sets and is easier to use. Adding helper methods Static_binary_string::q_append_wc() and String::append_wc(), to append a single wide character (a Unicode code point in my_wc_t). 2. storage/spider changes Removing spider_string::append_with_prefill(). It used String::append_with_prefix() inside, but it was unused itself. 3. Changing tricky charset incompatible code pieces in make_date_time() to compatible replacements: - Fixing the loop scanning the format string to iterate in terms of Unicode code points (using mb_wc()) rather than in terms of "char" items. - Using append_wc(my_wc_t) instead of append(char) to append a single character to the result string. - Using append_zerofill() instead of append_with_prefill() to append date/time numeric components to the result string.
This commit is contained in:
@ -392,6 +392,19 @@ public:
|
||||
float8store(Ptr + str_length, *d);
|
||||
str_length += 8;
|
||||
}
|
||||
/*
|
||||
Append a wide character.
|
||||
The caller must have allocated at least cs->mbmaxlen bytes.
|
||||
*/
|
||||
int q_append_wc(my_wc_t wc, CHARSET_INFO *cs)
|
||||
{
|
||||
int mblen;
|
||||
if ((mblen= cs->cset->wc_mb(cs, wc,
|
||||
(uchar *) end(),
|
||||
(uchar *) end() + cs->mbmaxlen)) > 0)
|
||||
str_length+= (uint32) mblen;
|
||||
return mblen;
|
||||
}
|
||||
void q_append(const char *data, size_t data_len)
|
||||
{
|
||||
if (data_len)
|
||||
@ -1009,8 +1022,6 @@ public:
|
||||
(quot && append(quot));
|
||||
}
|
||||
bool append(const char *s, size_t size);
|
||||
bool append_with_prefill(const char *s, uint32 arg_length,
|
||||
uint32 full_length, char fill_char);
|
||||
bool append_parenthesized(long nr, int radix= 10);
|
||||
|
||||
// Append with optional character set conversion from cs to charset()
|
||||
@ -1020,6 +1031,31 @@ public:
|
||||
return append(s.str, s.length, cs);
|
||||
}
|
||||
|
||||
// Append a wide character
|
||||
bool append_wc(my_wc_t wc)
|
||||
{
|
||||
if (reserve(mbmaxlen()))
|
||||
return true;
|
||||
int mblen= q_append_wc(wc, charset());
|
||||
if (mblen > 0)
|
||||
return false;
|
||||
else if (mblen == MY_CS_ILUNI && wc != '?')
|
||||
return q_append_wc('?', charset()) <= 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Append a number with zero prefilling
|
||||
bool append_zerofill(uint num, uint width)
|
||||
{
|
||||
static const char zeros[15]= "00000000000000";
|
||||
char intbuff[15];
|
||||
uint length= (uint) (int10_to_str(num, intbuff, 10) - intbuff);
|
||||
if (length < width &&
|
||||
append(zeros, width - length, &my_charset_latin1))
|
||||
return true;
|
||||
return append(intbuff, length, &my_charset_latin1);
|
||||
}
|
||||
|
||||
/*
|
||||
Append a bitmask in an uint32 with a translation into a
|
||||
C-style human readable representation, e.g.:
|
||||
|
Reference in New Issue
Block a user