Bug#13986705 CRASH IN GET_INTERVAL_VALUE() WITH DATE CALCULATION WITH UTF32 INTERVALS
This is a followup to the fix for Bug#12340997 get_interval_value() was trying to parse the input string, looking for leading '-' while skipping whitespace. The macro my_isspace() does not work for utf32 character set, since my_charset_utf32_general_ci.ctype == NULL. Solution: convert input to ASCII before parsing, and use the character set of the returned ASCII string.
This commit is contained in:
parent
bed97f20ae
commit
b0a2b7c1a9
@ -865,28 +865,43 @@ bool make_date_time(DATE_TIME_FORMAT *format, MYSQL_TIME *l_time,
|
|||||||
from the high end. This allows one to give:
|
from the high end. This allows one to give:
|
||||||
DAY_TO_SECOND as "D MM:HH:SS", "MM:HH:SS" "HH:SS" or as seconds.
|
DAY_TO_SECOND as "D MM:HH:SS", "MM:HH:SS" "HH:SS" or as seconds.
|
||||||
|
|
||||||
@param length: length of str
|
@param args item expression which we convert to an ASCII string
|
||||||
@param cs: charset of str
|
@param str_value string buffer
|
||||||
@param values: array of results
|
@param is_negative set to true if interval is prefixed by '-'
|
||||||
@param count: count of elements in result array
|
@param count: count of elements in result array
|
||||||
|
@param values: array of results
|
||||||
@param transform_msec: if value is true we suppose
|
@param transform_msec: if value is true we suppose
|
||||||
that the last part of string value is microseconds
|
that the last part of string value is microseconds
|
||||||
and we should transform value to six digit value.
|
and we should transform value to six digit value.
|
||||||
For example, '1.1' -> '1.100000'
|
For example, '1.1' -> '1.100000'
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static bool get_interval_info(const char *str,uint length,CHARSET_INFO *cs,
|
static bool get_interval_info(Item *args,
|
||||||
|
String *str_value,
|
||||||
|
bool *is_negative,
|
||||||
uint count, ulonglong *values,
|
uint count, ulonglong *values,
|
||||||
bool transform_msec)
|
bool transform_msec)
|
||||||
{
|
{
|
||||||
const char *end=str+length;
|
String *res;
|
||||||
uint i;
|
if (!(res= args->val_str_ascii(str_value)))
|
||||||
long msec_length= 0;
|
return true;
|
||||||
|
|
||||||
while (str != end && !my_isdigit(cs,*str))
|
CHARSET_INFO *cs= res->charset();
|
||||||
|
const char *str= res->ptr();
|
||||||
|
const char *end= str + res->length();
|
||||||
|
|
||||||
|
str+= cs->cset->scan(cs, str, end, MY_SEQ_SPACES);
|
||||||
|
if (str < end && *str == '-')
|
||||||
|
{
|
||||||
|
*is_negative= true;
|
||||||
|
str++;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (str < end && !my_isdigit(cs,*str))
|
||||||
str++;
|
str++;
|
||||||
|
|
||||||
for (i=0 ; i < count ; i++)
|
long msec_length= 0;
|
||||||
|
for (uint i=0 ; i < count ; i++)
|
||||||
{
|
{
|
||||||
longlong value;
|
longlong value;
|
||||||
const char *start= str;
|
const char *start= str;
|
||||||
@ -1427,45 +1442,24 @@ longlong Item_func_time_to_sec::val_int()
|
|||||||
To make code easy, allow interval objects without separators.
|
To make code easy, allow interval objects without separators.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bool get_interval_value(Item *args,interval_type int_type,
|
bool get_interval_value(Item *args, interval_type int_type,
|
||||||
String *str_value, INTERVAL *interval)
|
String *str_value, INTERVAL *interval)
|
||||||
{
|
{
|
||||||
ulonglong array[5];
|
ulonglong array[5];
|
||||||
longlong UNINIT_VAR(value);
|
longlong UNINIT_VAR(value);
|
||||||
const char *UNINIT_VAR(str);
|
|
||||||
size_t UNINIT_VAR(length);
|
|
||||||
CHARSET_INFO *cs=str_value->charset();
|
|
||||||
|
|
||||||
bzero((char*) interval,sizeof(*interval));
|
bzero((char*) interval,sizeof(*interval));
|
||||||
if ((int) int_type <= INTERVAL_MICROSECOND)
|
if ((int) int_type <= INTERVAL_MICROSECOND)
|
||||||
{
|
{
|
||||||
value= args->val_int();
|
value= args->val_int();
|
||||||
if (args->null_value)
|
if (args->null_value)
|
||||||
return 1;
|
return true;
|
||||||
if (value < 0)
|
if (value < 0)
|
||||||
{
|
{
|
||||||
interval->neg=1;
|
interval->neg= true;
|
||||||
value= -value;
|
value= -value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
String *res;
|
|
||||||
if (!(res= args->val_str_ascii(str_value)))
|
|
||||||
return (1);
|
|
||||||
|
|
||||||
/* record negative intervalls in interval->neg */
|
|
||||||
str=res->ptr();
|
|
||||||
const char *end=str+res->length();
|
|
||||||
while (str != end && my_isspace(cs,*str))
|
|
||||||
str++;
|
|
||||||
if (str != end && *str == '-')
|
|
||||||
{
|
|
||||||
interval->neg=1;
|
|
||||||
str++;
|
|
||||||
}
|
|
||||||
length= (size_t) (end-str); // Set up pointers to new str
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (int_type) {
|
switch (int_type) {
|
||||||
case INTERVAL_YEAR:
|
case INTERVAL_YEAR:
|
||||||
@ -1486,88 +1480,88 @@ bool get_interval_value(Item *args,interval_type int_type,
|
|||||||
case INTERVAL_HOUR:
|
case INTERVAL_HOUR:
|
||||||
interval->hour= (ulong) value;
|
interval->hour= (ulong) value;
|
||||||
break;
|
break;
|
||||||
case INTERVAL_MICROSECOND:
|
|
||||||
interval->second_part=value;
|
|
||||||
break;
|
|
||||||
case INTERVAL_MINUTE:
|
case INTERVAL_MINUTE:
|
||||||
interval->minute=value;
|
interval->minute=value;
|
||||||
break;
|
break;
|
||||||
case INTERVAL_SECOND:
|
case INTERVAL_SECOND:
|
||||||
interval->second=value;
|
interval->second=value;
|
||||||
break;
|
break;
|
||||||
|
case INTERVAL_MICROSECOND:
|
||||||
|
interval->second_part=value;
|
||||||
|
break;
|
||||||
case INTERVAL_YEAR_MONTH: // Allow YEAR-MONTH YYYYYMM
|
case INTERVAL_YEAR_MONTH: // Allow YEAR-MONTH YYYYYMM
|
||||||
if (get_interval_info(str,length,cs,2,array,0))
|
if (get_interval_info(args, str_value, &interval->neg, 2, array, false))
|
||||||
return (1);
|
return true;
|
||||||
interval->year= (ulong) array[0];
|
interval->year= (ulong) array[0];
|
||||||
interval->month= (ulong) array[1];
|
interval->month= (ulong) array[1];
|
||||||
break;
|
break;
|
||||||
case INTERVAL_DAY_HOUR:
|
case INTERVAL_DAY_HOUR:
|
||||||
if (get_interval_info(str,length,cs,2,array,0))
|
if (get_interval_info(args, str_value, &interval->neg, 2, array, false))
|
||||||
return (1);
|
return true;
|
||||||
interval->day= (ulong) array[0];
|
interval->day= (ulong) array[0];
|
||||||
interval->hour= (ulong) array[1];
|
interval->hour= (ulong) array[1];
|
||||||
break;
|
break;
|
||||||
|
case INTERVAL_DAY_MINUTE:
|
||||||
|
if (get_interval_info(args, str_value, &interval->neg, 3, array, false))
|
||||||
|
return true;
|
||||||
|
interval->day= (ulong) array[0];
|
||||||
|
interval->hour= (ulong) array[1];
|
||||||
|
interval->minute= array[2];
|
||||||
|
break;
|
||||||
|
case INTERVAL_DAY_SECOND:
|
||||||
|
if (get_interval_info(args, str_value, &interval->neg, 4, array, false))
|
||||||
|
return true;
|
||||||
|
interval->day= (ulong) array[0];
|
||||||
|
interval->hour= (ulong) array[1];
|
||||||
|
interval->minute= array[2];
|
||||||
|
interval->second= array[3];
|
||||||
|
break;
|
||||||
|
case INTERVAL_HOUR_MINUTE:
|
||||||
|
if (get_interval_info(args, str_value, &interval->neg, 2, array, false))
|
||||||
|
return true;
|
||||||
|
interval->hour= (ulong) array[0];
|
||||||
|
interval->minute= array[1];
|
||||||
|
break;
|
||||||
|
case INTERVAL_HOUR_SECOND:
|
||||||
|
if (get_interval_info(args, str_value, &interval->neg, 3, array, false))
|
||||||
|
return true;
|
||||||
|
interval->hour= (ulong) array[0];
|
||||||
|
interval->minute= array[1];
|
||||||
|
interval->second= array[2];
|
||||||
|
break;
|
||||||
|
case INTERVAL_MINUTE_SECOND:
|
||||||
|
if (get_interval_info(args, str_value, &interval->neg, 2, array, false))
|
||||||
|
return true;
|
||||||
|
interval->minute= array[0];
|
||||||
|
interval->second= array[1];
|
||||||
|
break;
|
||||||
case INTERVAL_DAY_MICROSECOND:
|
case INTERVAL_DAY_MICROSECOND:
|
||||||
if (get_interval_info(str,length,cs,5,array,1))
|
if (get_interval_info(args, str_value, &interval->neg, 5, array, true))
|
||||||
return (1);
|
return true;
|
||||||
interval->day= (ulong) array[0];
|
interval->day= (ulong) array[0];
|
||||||
interval->hour= (ulong) array[1];
|
interval->hour= (ulong) array[1];
|
||||||
interval->minute= array[2];
|
interval->minute= array[2];
|
||||||
interval->second= array[3];
|
interval->second= array[3];
|
||||||
interval->second_part= array[4];
|
interval->second_part= array[4];
|
||||||
break;
|
break;
|
||||||
case INTERVAL_DAY_MINUTE:
|
|
||||||
if (get_interval_info(str,length,cs,3,array,0))
|
|
||||||
return (1);
|
|
||||||
interval->day= (ulong) array[0];
|
|
||||||
interval->hour= (ulong) array[1];
|
|
||||||
interval->minute= array[2];
|
|
||||||
break;
|
|
||||||
case INTERVAL_DAY_SECOND:
|
|
||||||
if (get_interval_info(str,length,cs,4,array,0))
|
|
||||||
return (1);
|
|
||||||
interval->day= (ulong) array[0];
|
|
||||||
interval->hour= (ulong) array[1];
|
|
||||||
interval->minute= array[2];
|
|
||||||
interval->second= array[3];
|
|
||||||
break;
|
|
||||||
case INTERVAL_HOUR_MICROSECOND:
|
case INTERVAL_HOUR_MICROSECOND:
|
||||||
if (get_interval_info(str,length,cs,4,array,1))
|
if (get_interval_info(args, str_value, &interval->neg, 4, array, true))
|
||||||
return (1);
|
return true;
|
||||||
interval->hour= (ulong) array[0];
|
interval->hour= (ulong) array[0];
|
||||||
interval->minute= array[1];
|
interval->minute= array[1];
|
||||||
interval->second= array[2];
|
interval->second= array[2];
|
||||||
interval->second_part= array[3];
|
interval->second_part= array[3];
|
||||||
break;
|
break;
|
||||||
case INTERVAL_HOUR_MINUTE:
|
|
||||||
if (get_interval_info(str,length,cs,2,array,0))
|
|
||||||
return (1);
|
|
||||||
interval->hour= (ulong) array[0];
|
|
||||||
interval->minute= array[1];
|
|
||||||
break;
|
|
||||||
case INTERVAL_HOUR_SECOND:
|
|
||||||
if (get_interval_info(str,length,cs,3,array,0))
|
|
||||||
return (1);
|
|
||||||
interval->hour= (ulong) array[0];
|
|
||||||
interval->minute= array[1];
|
|
||||||
interval->second= array[2];
|
|
||||||
break;
|
|
||||||
case INTERVAL_MINUTE_MICROSECOND:
|
case INTERVAL_MINUTE_MICROSECOND:
|
||||||
if (get_interval_info(str,length,cs,3,array,1))
|
if (get_interval_info(args, str_value, &interval->neg, 3, array, true))
|
||||||
return (1);
|
return true;
|
||||||
interval->minute= array[0];
|
interval->minute= array[0];
|
||||||
interval->second= array[1];
|
interval->second= array[1];
|
||||||
interval->second_part= array[2];
|
interval->second_part= array[2];
|
||||||
break;
|
break;
|
||||||
case INTERVAL_MINUTE_SECOND:
|
|
||||||
if (get_interval_info(str,length,cs,2,array,0))
|
|
||||||
return (1);
|
|
||||||
interval->minute= array[0];
|
|
||||||
interval->second= array[1];
|
|
||||||
break;
|
|
||||||
case INTERVAL_SECOND_MICROSECOND:
|
case INTERVAL_SECOND_MICROSECOND:
|
||||||
if (get_interval_info(str,length,cs,2,array,1))
|
if (get_interval_info(args, str_value, &interval->neg, 2, array, true))
|
||||||
return (1);
|
return true;
|
||||||
interval->second= array[0];
|
interval->second= array[0];
|
||||||
interval->second_part= array[1];
|
interval->second_part= array[1];
|
||||||
break;
|
break;
|
||||||
@ -1575,7 +1569,7 @@ bool get_interval_value(Item *args,interval_type int_type,
|
|||||||
DBUG_ASSERT(0);
|
DBUG_ASSERT(0);
|
||||||
break; /* purecov: end */
|
break; /* purecov: end */
|
||||||
}
|
}
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user