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:
parent
3626379d42
commit
e2da748c29
@ -3394,5 +3394,49 @@ INSERT INTO t VALUES (0,0);
|
|||||||
DELETE FROM t WHERE c2<c1;
|
DELETE FROM t WHERE c2<c1;
|
||||||
DROP TABLE t;
|
DROP TABLE t;
|
||||||
#
|
#
|
||||||
|
# MDEV-28835 Assertion `(length % 4) == 0' failed in my_lengthsp_utf32 on INSERT
|
||||||
|
#
|
||||||
|
SET NAMES latin1,character_set_connection=binary;
|
||||||
|
# Binary format, binary result
|
||||||
|
SELECT DATE_FORMAT('2004-02-02','%W');
|
||||||
|
DATE_FORMAT('2004-02-02','%W')
|
||||||
|
Monday
|
||||||
|
SELECT HEX(DATE_FORMAT('2004-02-02','%W'));
|
||||||
|
HEX(DATE_FORMAT('2004-02-02','%W'))
|
||||||
|
4D6F6E646179
|
||||||
|
SELECT DATE_FORMAT(TIME'-01:01:01','%h');
|
||||||
|
DATE_FORMAT(TIME'-01:01:01','%h')
|
||||||
|
-01
|
||||||
|
SELECT HEX(DATE_FORMAT(TIME'-01:01:01','%h'));
|
||||||
|
HEX(DATE_FORMAT(TIME'-01:01:01','%h'))
|
||||||
|
2D3031
|
||||||
|
# latin1 format, binary result
|
||||||
|
SELECT DATE_FORMAT('2004-02-02',_latin1'%W');
|
||||||
|
DATE_FORMAT('2004-02-02',_latin1'%W')
|
||||||
|
Monday
|
||||||
|
SELECT HEX(DATE_FORMAT('2004-02-02',_latin1'%W'));
|
||||||
|
HEX(DATE_FORMAT('2004-02-02',_latin1'%W'))
|
||||||
|
4D6F6E646179
|
||||||
|
SELECT DATE_FORMAT(TIME'-01:01:01',_latin1'%h');
|
||||||
|
DATE_FORMAT(TIME'-01:01:01',_latin1'%h')
|
||||||
|
-01
|
||||||
|
SELECT HEX(DATE_FORMAT(TIME'-01:01:01',_latin1'%h'));
|
||||||
|
HEX(DATE_FORMAT(TIME'-01:01:01',_latin1'%h'))
|
||||||
|
2D3031
|
||||||
|
# Binary format, latin1 result
|
||||||
|
SET NAMES latin1;
|
||||||
|
SELECT DATE_FORMAT('2004-02-02',_binary'%W');
|
||||||
|
DATE_FORMAT('2004-02-02',_binary'%W')
|
||||||
|
Monday
|
||||||
|
SELECT HEX(DATE_FORMAT('2004-02-02',_binary'%W'));
|
||||||
|
HEX(DATE_FORMAT('2004-02-02',_binary'%W'))
|
||||||
|
4D6F6E646179
|
||||||
|
SELECT DATE_FORMAT(TIME'-01:01:01',_binary'%h');
|
||||||
|
DATE_FORMAT(TIME'-01:01:01',_binary'%h')
|
||||||
|
-01
|
||||||
|
SELECT HEX(DATE_FORMAT(TIME'-01:01:01',_binary'%h'));
|
||||||
|
HEX(DATE_FORMAT(TIME'-01:01:01',_binary'%h'))
|
||||||
|
2D3031
|
||||||
|
#
|
||||||
# End of 10.4 tests
|
# End of 10.4 tests
|
||||||
#
|
#
|
||||||
|
@ -241,6 +241,31 @@ INSERT INTO t VALUES (0,0);
|
|||||||
DELETE FROM t WHERE c2<c1;
|
DELETE FROM t WHERE c2<c1;
|
||||||
DROP TABLE t;
|
DROP TABLE t;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-28835 Assertion `(length % 4) == 0' failed in my_lengthsp_utf32 on INSERT
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
SET NAMES latin1,character_set_connection=binary;
|
||||||
|
|
||||||
|
--echo # Binary format, binary result
|
||||||
|
SELECT DATE_FORMAT('2004-02-02','%W');
|
||||||
|
SELECT HEX(DATE_FORMAT('2004-02-02','%W'));
|
||||||
|
SELECT DATE_FORMAT(TIME'-01:01:01','%h');
|
||||||
|
SELECT HEX(DATE_FORMAT(TIME'-01:01:01','%h'));
|
||||||
|
|
||||||
|
--echo # latin1 format, binary result
|
||||||
|
SELECT DATE_FORMAT('2004-02-02',_latin1'%W');
|
||||||
|
SELECT HEX(DATE_FORMAT('2004-02-02',_latin1'%W'));
|
||||||
|
SELECT DATE_FORMAT(TIME'-01:01:01',_latin1'%h');
|
||||||
|
SELECT HEX(DATE_FORMAT(TIME'-01:01:01',_latin1'%h'));
|
||||||
|
|
||||||
|
--echo # Binary format, latin1 result
|
||||||
|
SET NAMES latin1;
|
||||||
|
SELECT DATE_FORMAT('2004-02-02',_binary'%W');
|
||||||
|
SELECT HEX(DATE_FORMAT('2004-02-02',_binary'%W'));
|
||||||
|
SELECT DATE_FORMAT(TIME'-01:01:01',_binary'%h');
|
||||||
|
SELECT HEX(DATE_FORMAT(TIME'-01:01:01',_binary'%h'));
|
||||||
|
|
||||||
--echo #
|
--echo #
|
||||||
--echo # End of 10.4 tests
|
--echo # End of 10.4 tests
|
||||||
--echo #
|
--echo #
|
||||||
|
@ -2958,5 +2958,69 @@ HEX(OCT(a))
|
|||||||
DROP TABLE t;
|
DROP TABLE t;
|
||||||
SET NAMES utf8;
|
SET NAMES utf8;
|
||||||
#
|
#
|
||||||
|
# MDEV-28835 Assertion `(length % 4) == 0' failed in my_lengthsp_utf32 on INSERT
|
||||||
|
#
|
||||||
|
SET sql_mode='',character_set_connection=utf32;
|
||||||
|
CREATE TABLE t (c ENUM ('','')) CHARACTER SET utf32;
|
||||||
|
Warnings:
|
||||||
|
Note 1291 Column 'c' has duplicated value '' in ENUM
|
||||||
|
INSERT INTO t VALUES (DATE_FORMAT('2004-02-02','%W'));
|
||||||
|
Warnings:
|
||||||
|
Warning 1265 Data truncated for column 'c' at row 1
|
||||||
|
DROP TABLE t;
|
||||||
|
SET sql_mode=DEFAULT;
|
||||||
|
# utf32 format, utf32 result
|
||||||
|
SELECT DATE_FORMAT('2004-02-02','%W');
|
||||||
|
DATE_FORMAT('2004-02-02','%W')
|
||||||
|
Monday
|
||||||
|
SELECT HEX(DATE_FORMAT('2004-02-02','%W'));
|
||||||
|
HEX(DATE_FORMAT('2004-02-02','%W'))
|
||||||
|
0000004D0000006F0000006E000000640000006100000079
|
||||||
|
SELECT DATE_FORMAT(TIME'-01:01:01','%h');
|
||||||
|
DATE_FORMAT(TIME'-01:01:01','%h')
|
||||||
|
-01
|
||||||
|
SELECT HEX(DATE_FORMAT(TIME'-01:01:01','%h'));
|
||||||
|
HEX(DATE_FORMAT(TIME'-01:01:01','%h'))
|
||||||
|
0000002D0000003000000031
|
||||||
|
# utf8 format, utf32 result
|
||||||
|
SELECT DATE_FORMAT('2004-02-02',_utf8'%W');
|
||||||
|
DATE_FORMAT('2004-02-02',_utf8'%W')
|
||||||
|
Monday
|
||||||
|
SELECT HEX(DATE_FORMAT('2004-02-02',_utf8'%W'));
|
||||||
|
HEX(DATE_FORMAT('2004-02-02',_utf8'%W'))
|
||||||
|
0000004D0000006F0000006E000000640000006100000079
|
||||||
|
SELECT DATE_FORMAT(TIME'-01:01:01',_utf8'%h');
|
||||||
|
DATE_FORMAT(TIME'-01:01:01',_utf8'%h')
|
||||||
|
-01
|
||||||
|
SELECT HEX(DATE_FORMAT(TIME'-01:01:01',_utf8'%h'));
|
||||||
|
HEX(DATE_FORMAT(TIME'-01:01:01',_utf8'%h'))
|
||||||
|
0000002D0000003000000031
|
||||||
|
# utf32 format, utf8 result
|
||||||
|
SET NAMES utf8;
|
||||||
|
SELECT DATE_FORMAT('2004-02-02',CONVERT('%W' USING utf32));
|
||||||
|
DATE_FORMAT('2004-02-02',CONVERT('%W' USING utf32))
|
||||||
|
Monday
|
||||||
|
SELECT HEX(DATE_FORMAT('2004-02-02',CONVERT('%W' USING utf32)));
|
||||||
|
HEX(DATE_FORMAT('2004-02-02',CONVERT('%W' USING utf32)))
|
||||||
|
4D6F6E646179
|
||||||
|
SELECT DATE_FORMAT(TIME'-01:01:01',CONVERT('%h' USING utf32));
|
||||||
|
DATE_FORMAT(TIME'-01:01:01',CONVERT('%h' USING utf32))
|
||||||
|
-01
|
||||||
|
SELECT HEX(DATE_FORMAT(TIME'-01:01:01',CONVERT('%h' USING utf32)));
|
||||||
|
HEX(DATE_FORMAT(TIME'-01:01:01',CONVERT('%h' USING utf32)))
|
||||||
|
2D3031
|
||||||
|
# non-BMP characters in format, utf8mb3 result
|
||||||
|
# expect non-convertable characters to be replaced to '?'
|
||||||
|
SET NAMES utf8mb3;
|
||||||
|
SET @format= CONCAT(CONVERT('%h' USING utf32),
|
||||||
|
_utf32 0x0010FFFF /*a non-BMP character*/,
|
||||||
|
CONVERT('%i' USING utf32));
|
||||||
|
SELECT DATE_FORMAT(TIME'11:22:33',@format);
|
||||||
|
DATE_FORMAT(TIME'11:22:33',@format)
|
||||||
|
11?22
|
||||||
|
SELECT HEX(DATE_FORMAT(TIME'11:22:33',@format));
|
||||||
|
HEX(DATE_FORMAT(TIME'11:22:33',@format))
|
||||||
|
31313F3232
|
||||||
|
#
|
||||||
# End of 10.4 tests
|
# End of 10.4 tests
|
||||||
#
|
#
|
||||||
|
@ -1120,6 +1120,48 @@ SELECT HEX(OCT(a)) FROM t;
|
|||||||
DROP TABLE t;
|
DROP TABLE t;
|
||||||
SET NAMES utf8;
|
SET NAMES utf8;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-28835 Assertion `(length % 4) == 0' failed in my_lengthsp_utf32 on INSERT
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
# --view-protocol does not yet work well with character set introducers
|
||||||
|
|
||||||
|
--disable_view_protocol
|
||||||
|
|
||||||
|
SET sql_mode='',character_set_connection=utf32;
|
||||||
|
CREATE TABLE t (c ENUM ('','')) CHARACTER SET utf32;
|
||||||
|
INSERT INTO t VALUES (DATE_FORMAT('2004-02-02','%W'));
|
||||||
|
DROP TABLE t;
|
||||||
|
SET sql_mode=DEFAULT;
|
||||||
|
|
||||||
|
--echo # utf32 format, utf32 result
|
||||||
|
SELECT DATE_FORMAT('2004-02-02','%W');
|
||||||
|
SELECT HEX(DATE_FORMAT('2004-02-02','%W'));
|
||||||
|
SELECT DATE_FORMAT(TIME'-01:01:01','%h');
|
||||||
|
SELECT HEX(DATE_FORMAT(TIME'-01:01:01','%h'));
|
||||||
|
|
||||||
|
--echo # utf8 format, utf32 result
|
||||||
|
SELECT DATE_FORMAT('2004-02-02',_utf8'%W');
|
||||||
|
SELECT HEX(DATE_FORMAT('2004-02-02',_utf8'%W'));
|
||||||
|
SELECT DATE_FORMAT(TIME'-01:01:01',_utf8'%h');
|
||||||
|
SELECT HEX(DATE_FORMAT(TIME'-01:01:01',_utf8'%h'));
|
||||||
|
|
||||||
|
--echo # utf32 format, utf8 result
|
||||||
|
SET NAMES utf8;
|
||||||
|
SELECT DATE_FORMAT('2004-02-02',CONVERT('%W' USING utf32));
|
||||||
|
SELECT HEX(DATE_FORMAT('2004-02-02',CONVERT('%W' USING utf32)));
|
||||||
|
SELECT DATE_FORMAT(TIME'-01:01:01',CONVERT('%h' USING utf32));
|
||||||
|
SELECT HEX(DATE_FORMAT(TIME'-01:01:01',CONVERT('%h' USING utf32)));
|
||||||
|
|
||||||
|
--echo # non-BMP characters in format, utf8mb3 result
|
||||||
|
--echo # expect non-convertable characters to be replaced to '?'
|
||||||
|
SET NAMES utf8mb3;
|
||||||
|
SET @format= CONCAT(CONVERT('%h' USING utf32),
|
||||||
|
_utf32 0x0010FFFF /*a non-BMP character*/,
|
||||||
|
CONVERT('%i' USING utf32));
|
||||||
|
SELECT DATE_FORMAT(TIME'11:22:33',@format);
|
||||||
|
SELECT HEX(DATE_FORMAT(TIME'11:22:33',@format));
|
||||||
|
--enable_view_protocol
|
||||||
|
|
||||||
--echo #
|
--echo #
|
||||||
--echo # End of 10.4 tests
|
--echo # End of 10.4 tests
|
||||||
|
@ -478,7 +478,9 @@ err:
|
|||||||
Create a formatted date/time value in a string.
|
Create a formatted date/time value in a string.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static bool make_date_time(const LEX_CSTRING &format, MYSQL_TIME *l_time,
|
static bool make_date_time(const LEX_CSTRING &format,
|
||||||
|
CHARSET_INFO *format_charset,
|
||||||
|
MYSQL_TIME *l_time,
|
||||||
timestamp_type type, const MY_LOCALE *locale,
|
timestamp_type type, const MY_LOCALE *locale,
|
||||||
String *str)
|
String *str)
|
||||||
{
|
{
|
||||||
@ -486,21 +488,33 @@ static bool make_date_time(const LEX_CSTRING &format, MYSQL_TIME *l_time,
|
|||||||
uint hours_i;
|
uint hours_i;
|
||||||
uint weekday;
|
uint weekday;
|
||||||
ulong length;
|
ulong length;
|
||||||
const char *ptr, *end;
|
const uchar *ptr, *end;
|
||||||
|
|
||||||
str->length(0);
|
str->length(0);
|
||||||
|
|
||||||
if (l_time->neg)
|
if (l_time->neg)
|
||||||
str->append('-');
|
str->append_wc('-');
|
||||||
|
|
||||||
end= (ptr= format.str) + format.length;
|
end= (ptr= (const uchar *) format.str) + format.length;
|
||||||
for (; ptr != end ; ptr++)
|
|
||||||
|
for ( ; ; )
|
||||||
{
|
{
|
||||||
if (*ptr != '%' || ptr+1 == end)
|
my_wc_t wc;
|
||||||
str->append(*ptr);
|
int mblen= format_charset->cset->mb_wc(format_charset, &wc, ptr, end);
|
||||||
|
if (mblen < 1)
|
||||||
|
return false;
|
||||||
|
ptr+= mblen;
|
||||||
|
|
||||||
|
if (wc != '%' || ptr >= end)
|
||||||
|
str->append_wc(wc);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
switch (*++ptr) {
|
mblen= format_charset->cset->mb_wc(format_charset, &wc, ptr, end);
|
||||||
|
if (mblen < 1)
|
||||||
|
return false;
|
||||||
|
ptr+= mblen;
|
||||||
|
|
||||||
|
switch (wc) {
|
||||||
case 'M':
|
case 'M':
|
||||||
if (type == MYSQL_TIMESTAMP_TIME || !l_time->month)
|
if (type == MYSQL_TIMESTAMP_TIME || !l_time->month)
|
||||||
return 1;
|
return 1;
|
||||||
@ -536,8 +550,7 @@ static bool make_date_time(const LEX_CSTRING &format, MYSQL_TIME *l_time,
|
|||||||
case 'D':
|
case 'D':
|
||||||
if (type == MYSQL_TIMESTAMP_TIME)
|
if (type == MYSQL_TIMESTAMP_TIME)
|
||||||
return 1;
|
return 1;
|
||||||
length= (uint) (int10_to_str(l_time->day, intbuff, 10) - intbuff);
|
str->append_zerofill(l_time->day, 1);
|
||||||
str->append_with_prefill(intbuff, length, 1, '0');
|
|
||||||
if (l_time->day >= 10 && l_time->day <= 19)
|
if (l_time->day >= 10 && l_time->day <= 19)
|
||||||
str->append(STRING_WITH_LEN("th"));
|
str->append(STRING_WITH_LEN("th"));
|
||||||
else
|
else
|
||||||
@ -561,73 +574,62 @@ static bool make_date_time(const LEX_CSTRING &format, MYSQL_TIME *l_time,
|
|||||||
case 'Y':
|
case 'Y':
|
||||||
if (type == MYSQL_TIMESTAMP_TIME)
|
if (type == MYSQL_TIMESTAMP_TIME)
|
||||||
return 1;
|
return 1;
|
||||||
length= (uint) (int10_to_str(l_time->year, intbuff, 10) - intbuff);
|
str->append_zerofill(l_time->year, 4);
|
||||||
str->append_with_prefill(intbuff, length, 4, '0');
|
|
||||||
break;
|
break;
|
||||||
case 'y':
|
case 'y':
|
||||||
if (type == MYSQL_TIMESTAMP_TIME)
|
if (type == MYSQL_TIMESTAMP_TIME)
|
||||||
return 1;
|
return 1;
|
||||||
length= (uint) (int10_to_str(l_time->year%100, intbuff, 10) - intbuff);
|
str->append_zerofill(l_time->year % 100, 2);
|
||||||
str->append_with_prefill(intbuff, length, 2, '0');
|
|
||||||
break;
|
break;
|
||||||
case 'm':
|
case 'm':
|
||||||
if (type == MYSQL_TIMESTAMP_TIME)
|
if (type == MYSQL_TIMESTAMP_TIME)
|
||||||
return 1;
|
return 1;
|
||||||
length= (uint) (int10_to_str(l_time->month, intbuff, 10) - intbuff);
|
str->append_zerofill(l_time->month, 2);
|
||||||
str->append_with_prefill(intbuff, length, 2, '0');
|
|
||||||
break;
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
if (type == MYSQL_TIMESTAMP_TIME)
|
if (type == MYSQL_TIMESTAMP_TIME)
|
||||||
return 1;
|
return 1;
|
||||||
length= (uint) (int10_to_str(l_time->month, intbuff, 10) - intbuff);
|
str->append_zerofill(l_time->month, 1);
|
||||||
str->append_with_prefill(intbuff, length, 1, '0');
|
|
||||||
break;
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
if (type == MYSQL_TIMESTAMP_TIME)
|
if (type == MYSQL_TIMESTAMP_TIME)
|
||||||
return 1;
|
return 1;
|
||||||
length= (uint) (int10_to_str(l_time->day, intbuff, 10) - intbuff);
|
str->append_zerofill(l_time->day, 2);
|
||||||
str->append_with_prefill(intbuff, length, 2, '0');
|
|
||||||
break;
|
break;
|
||||||
case 'e':
|
case 'e':
|
||||||
if (type == MYSQL_TIMESTAMP_TIME)
|
if (type == MYSQL_TIMESTAMP_TIME)
|
||||||
return 1;
|
return 1;
|
||||||
length= (uint) (int10_to_str(l_time->day, intbuff, 10) - intbuff);
|
str->append_zerofill(l_time->day, 1);
|
||||||
str->append_with_prefill(intbuff, length, 1, '0');
|
|
||||||
break;
|
break;
|
||||||
case 'f':
|
case 'f':
|
||||||
length= (uint) (int10_to_str(l_time->second_part, intbuff, 10) - intbuff);
|
str->append_zerofill((uint) l_time->second_part, 6);
|
||||||
str->append_with_prefill(intbuff, length, 6, '0');
|
|
||||||
break;
|
break;
|
||||||
case 'H':
|
case 'H':
|
||||||
length= (uint) (int10_to_str(l_time->hour, intbuff, 10) - intbuff);
|
str->append_zerofill(l_time->hour, 2);
|
||||||
str->append_with_prefill(intbuff, length, 2, '0');
|
|
||||||
break;
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
case 'I':
|
case 'I':
|
||||||
hours_i= (l_time->hour%24 + 11)%12+1;
|
hours_i= (l_time->hour%24 + 11)%12+1;
|
||||||
length= (uint) (int10_to_str(hours_i, intbuff, 10) - intbuff);
|
str->append_zerofill(hours_i, 2);
|
||||||
str->append_with_prefill(intbuff, length, 2, '0');
|
|
||||||
break;
|
break;
|
||||||
case 'i': /* minutes */
|
case 'i': /* minutes */
|
||||||
length= (uint) (int10_to_str(l_time->minute, intbuff, 10) - intbuff);
|
str->append_zerofill(l_time->minute, 2);
|
||||||
str->append_with_prefill(intbuff, length, 2, '0');
|
|
||||||
break;
|
break;
|
||||||
case 'j':
|
case 'j':
|
||||||
|
{
|
||||||
if (type == MYSQL_TIMESTAMP_TIME || !l_time->month || !l_time->year)
|
if (type == MYSQL_TIMESTAMP_TIME || !l_time->month || !l_time->year)
|
||||||
return 1;
|
return 1;
|
||||||
length= (uint) (int10_to_str(calc_daynr(l_time->year,l_time->month,
|
long value= calc_daynr(l_time->year,l_time->month, l_time->day) -
|
||||||
l_time->day) -
|
calc_daynr(l_time->year,1,1) + 1;
|
||||||
calc_daynr(l_time->year,1,1) + 1, intbuff, 10) - intbuff);
|
str->append_zerofill((uint) value, 3);
|
||||||
str->append_with_prefill(intbuff, length, 3, '0');
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case 'k':
|
case 'k':
|
||||||
length= (uint) (int10_to_str(l_time->hour, intbuff, 10) - intbuff);
|
str->append_zerofill(l_time->hour, 1);
|
||||||
str->append_with_prefill(intbuff, length, 1, '0');
|
|
||||||
break;
|
break;
|
||||||
case 'l':
|
case 'l':
|
||||||
hours_i= (l_time->hour%24 + 11)%12+1;
|
hours_i= (l_time->hour%24 + 11)%12+1;
|
||||||
length= (uint) (int10_to_str(hours_i, intbuff, 10) - intbuff);
|
str->append_zerofill(hours_i, 1);
|
||||||
str->append_with_prefill(intbuff, length, 1, '0');
|
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
hours_i= l_time->hour%24;
|
hours_i= l_time->hour%24;
|
||||||
@ -643,8 +645,7 @@ static bool make_date_time(const LEX_CSTRING &format, MYSQL_TIME *l_time,
|
|||||||
break;
|
break;
|
||||||
case 'S':
|
case 'S':
|
||||||
case 's':
|
case 's':
|
||||||
length= (uint) (int10_to_str(l_time->second, intbuff, 10) - intbuff);
|
str->append_zerofill(l_time->second, 2);
|
||||||
str->append_with_prefill(intbuff, length, 2, '0');
|
|
||||||
break;
|
break;
|
||||||
case 'T':
|
case 'T':
|
||||||
length= sprintf(intbuff, "%02d:%02d:%02d",
|
length= sprintf(intbuff, "%02d:%02d:%02d",
|
||||||
@ -657,42 +658,39 @@ static bool make_date_time(const LEX_CSTRING &format, MYSQL_TIME *l_time,
|
|||||||
uint year;
|
uint year;
|
||||||
if (type == MYSQL_TIMESTAMP_TIME)
|
if (type == MYSQL_TIMESTAMP_TIME)
|
||||||
return 1;
|
return 1;
|
||||||
length= (uint) (int10_to_str(calc_week(l_time,
|
|
||||||
(*ptr) == 'U' ?
|
uint value= calc_week(l_time,
|
||||||
WEEK_FIRST_WEEKDAY : WEEK_MONDAY_FIRST,
|
wc == 'U' ? WEEK_FIRST_WEEKDAY :
|
||||||
&year),
|
WEEK_MONDAY_FIRST,
|
||||||
intbuff, 10) - intbuff);
|
&year);
|
||||||
str->append_with_prefill(intbuff, length, 2, '0');
|
str->append_zerofill(value, 2);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
case 'V':
|
case 'V':
|
||||||
{
|
{
|
||||||
uint year;
|
uint year;
|
||||||
if (type == MYSQL_TIMESTAMP_TIME)
|
if (type == MYSQL_TIMESTAMP_TIME)
|
||||||
return 1;
|
return 1;
|
||||||
length= (uint) (int10_to_str(calc_week(l_time,
|
uint value= calc_week(l_time, wc == 'V' ?
|
||||||
((*ptr) == 'V' ?
|
(WEEK_YEAR | WEEK_FIRST_WEEKDAY) :
|
||||||
(WEEK_YEAR | WEEK_FIRST_WEEKDAY) :
|
(WEEK_YEAR | WEEK_MONDAY_FIRST),
|
||||||
(WEEK_YEAR | WEEK_MONDAY_FIRST)),
|
&year);
|
||||||
&year),
|
str->append_zerofill(value, 2);
|
||||||
intbuff, 10) - intbuff);
|
|
||||||
str->append_with_prefill(intbuff, length, 2, '0');
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'x':
|
case 'x':
|
||||||
case 'X':
|
case 'X':
|
||||||
{
|
{
|
||||||
uint year;
|
uint year;
|
||||||
if (type == MYSQL_TIMESTAMP_TIME)
|
if (type == MYSQL_TIMESTAMP_TIME)
|
||||||
return 1;
|
return 1;
|
||||||
(void) calc_week(l_time,
|
(void) calc_week(l_time,
|
||||||
((*ptr) == 'X' ?
|
(wc == 'X' ?
|
||||||
WEEK_YEAR | WEEK_FIRST_WEEKDAY :
|
WEEK_YEAR | WEEK_FIRST_WEEKDAY :
|
||||||
WEEK_YEAR | WEEK_MONDAY_FIRST),
|
WEEK_YEAR | WEEK_MONDAY_FIRST),
|
||||||
&year);
|
&year);
|
||||||
length= (uint) (int10_to_str(year, intbuff, 10) - intbuff);
|
str->append_zerofill(year, 4);
|
||||||
str->append_with_prefill(intbuff, length, 4, '0');
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'w':
|
case 'w':
|
||||||
@ -700,12 +698,11 @@ static bool make_date_time(const LEX_CSTRING &format, MYSQL_TIME *l_time,
|
|||||||
return 1;
|
return 1;
|
||||||
weekday=calc_weekday(calc_daynr(l_time->year,l_time->month,
|
weekday=calc_weekday(calc_daynr(l_time->year,l_time->month,
|
||||||
l_time->day),1);
|
l_time->day),1);
|
||||||
length= (uint) (int10_to_str(weekday, intbuff, 10) - intbuff);
|
str->append_zerofill(weekday, 1);
|
||||||
str->append_with_prefill(intbuff, length, 1, '0');
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
str->append(*ptr);
|
str->append_wc(wc);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1919,7 +1916,7 @@ String *Item_func_date_format::val_str(String *str)
|
|||||||
|
|
||||||
/* Create the result string */
|
/* Create the result string */
|
||||||
str->set_charset(collation.collation);
|
str->set_charset(collation.collation);
|
||||||
if (!make_date_time(format->lex_cstring(), &l_time,
|
if (!make_date_time(format->lex_cstring(), format->charset(), &l_time,
|
||||||
is_time_format ? MYSQL_TIMESTAMP_TIME :
|
is_time_format ? MYSQL_TIMESTAMP_TIME :
|
||||||
MYSQL_TIMESTAMP_DATE,
|
MYSQL_TIMESTAMP_DATE,
|
||||||
lc, str))
|
lc, str))
|
||||||
|
@ -649,24 +649,6 @@ bool String::append_parenthesized(long nr, int radix)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool String::append_with_prefill(const char *s,uint32 arg_length,
|
|
||||||
uint32 full_length, char fill_char)
|
|
||||||
{
|
|
||||||
int t_length= arg_length > full_length ? arg_length : full_length;
|
|
||||||
|
|
||||||
if (realloc_with_extra_if_needed(str_length + t_length))
|
|
||||||
return TRUE;
|
|
||||||
t_length= full_length - arg_length;
|
|
||||||
if (t_length > 0)
|
|
||||||
{
|
|
||||||
bfill(Ptr+str_length, t_length, fill_char);
|
|
||||||
str_length=str_length + t_length;
|
|
||||||
}
|
|
||||||
append(s, arg_length);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int Static_binary_string::strstr(const Static_binary_string &s, uint32 offset)
|
int Static_binary_string::strstr(const Static_binary_string &s, uint32 offset)
|
||||||
{
|
{
|
||||||
if (s.length()+offset <= str_length)
|
if (s.length()+offset <= str_length)
|
||||||
|
@ -392,6 +392,19 @@ public:
|
|||||||
float8store(Ptr + str_length, *d);
|
float8store(Ptr + str_length, *d);
|
||||||
str_length += 8;
|
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)
|
void q_append(const char *data, size_t data_len)
|
||||||
{
|
{
|
||||||
if (data_len)
|
if (data_len)
|
||||||
@ -1009,8 +1022,6 @@ public:
|
|||||||
(quot && append(quot));
|
(quot && append(quot));
|
||||||
}
|
}
|
||||||
bool append(const char *s, size_t size);
|
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);
|
bool append_parenthesized(long nr, int radix= 10);
|
||||||
|
|
||||||
// Append with optional character set conversion from cs to charset()
|
// Append with optional character set conversion from cs to charset()
|
||||||
@ -1020,6 +1031,31 @@ public:
|
|||||||
return append(s.str, s.length, cs);
|
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
|
Append a bitmask in an uint32 with a translation into a
|
||||||
C-style human readable representation, e.g.:
|
C-style human readable representation, e.g.:
|
||||||
|
@ -445,12 +445,6 @@ public:
|
|||||||
IO_CACHE *file,
|
IO_CACHE *file,
|
||||||
uint32 arg_length
|
uint32 arg_length
|
||||||
);
|
);
|
||||||
bool append_with_prefill(
|
|
||||||
const char *s,
|
|
||||||
uint32 arg_length,
|
|
||||||
uint32 full_length,
|
|
||||||
char fill_char
|
|
||||||
);
|
|
||||||
int strstr(
|
int strstr(
|
||||||
const String &search,
|
const String &search,
|
||||||
uint32 offset = 0
|
uint32 offset = 0
|
||||||
|
@ -941,23 +941,6 @@ bool spider_string::append(
|
|||||||
DBUG_RETURN(res);
|
DBUG_RETURN(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool spider_string::append_with_prefill(
|
|
||||||
const char *s,
|
|
||||||
uint32 arg_length,
|
|
||||||
uint32 full_length,
|
|
||||||
char fill_char
|
|
||||||
) {
|
|
||||||
DBUG_ENTER("spider_string::append_with_prefill");
|
|
||||||
DBUG_PRINT("info",("spider this=%p", this));
|
|
||||||
DBUG_ASSERT(mem_calc_inited);
|
|
||||||
DBUG_ASSERT((!current_alloc_mem && !str.is_alloced()) ||
|
|
||||||
current_alloc_mem == str.alloced_length());
|
|
||||||
bool res = str.append_with_prefill(s, arg_length, full_length,
|
|
||||||
fill_char);
|
|
||||||
SPIDER_STRING_CALC_MEM;
|
|
||||||
DBUG_RETURN(res);
|
|
||||||
}
|
|
||||||
|
|
||||||
int spider_string::strstr(
|
int spider_string::strstr(
|
||||||
const String &search,
|
const String &search,
|
||||||
uint32 offset
|
uint32 offset
|
||||||
|
Loading…
x
Reference in New Issue
Block a user