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:
|
||||
DAY_TO_SECOND as "D MM:HH:SS", "MM:HH:SS" "HH:SS" or as seconds.
|
||||
|
||||
@param length: length of str
|
||||
@param cs: charset of str
|
||||
@param values: array of results
|
||||
@param args item expression which we convert to an ASCII string
|
||||
@param str_value string buffer
|
||||
@param is_negative set to true if interval is prefixed by '-'
|
||||
@param count: count of elements in result array
|
||||
@param values: array of results
|
||||
@param transform_msec: if value is true we suppose
|
||||
that the last part of string value is microseconds
|
||||
and we should transform value to six digit value.
|
||||
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,
|
||||
bool transform_msec)
|
||||
{
|
||||
const char *end=str+length;
|
||||
uint i;
|
||||
long msec_length= 0;
|
||||
String *res;
|
||||
if (!(res= args->val_str_ascii(str_value)))
|
||||
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++;
|
||||
|
||||
for (i=0 ; i < count ; i++)
|
||||
long msec_length= 0;
|
||||
for (uint i=0 ; i < count ; i++)
|
||||
{
|
||||
longlong value;
|
||||
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.
|
||||
*/
|
||||
|
||||
bool get_interval_value(Item *args,interval_type int_type,
|
||||
String *str_value, INTERVAL *interval)
|
||||
bool get_interval_value(Item *args, interval_type int_type,
|
||||
String *str_value, INTERVAL *interval)
|
||||
{
|
||||
ulonglong array[5];
|
||||
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));
|
||||
if ((int) int_type <= INTERVAL_MICROSECOND)
|
||||
{
|
||||
value= args->val_int();
|
||||
if (args->null_value)
|
||||
return 1;
|
||||
return true;
|
||||
if (value < 0)
|
||||
{
|
||||
interval->neg=1;
|
||||
interval->neg= true;
|
||||
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) {
|
||||
case INTERVAL_YEAR:
|
||||
@ -1486,88 +1480,88 @@ bool get_interval_value(Item *args,interval_type int_type,
|
||||
case INTERVAL_HOUR:
|
||||
interval->hour= (ulong) value;
|
||||
break;
|
||||
case INTERVAL_MICROSECOND:
|
||||
interval->second_part=value;
|
||||
break;
|
||||
case INTERVAL_MINUTE:
|
||||
interval->minute=value;
|
||||
break;
|
||||
case INTERVAL_SECOND:
|
||||
interval->second=value;
|
||||
break;
|
||||
case INTERVAL_MICROSECOND:
|
||||
interval->second_part=value;
|
||||
break;
|
||||
case INTERVAL_YEAR_MONTH: // Allow YEAR-MONTH YYYYYMM
|
||||
if (get_interval_info(str,length,cs,2,array,0))
|
||||
return (1);
|
||||
if (get_interval_info(args, str_value, &interval->neg, 2, array, false))
|
||||
return true;
|
||||
interval->year= (ulong) array[0];
|
||||
interval->month= (ulong) array[1];
|
||||
break;
|
||||
case INTERVAL_DAY_HOUR:
|
||||
if (get_interval_info(str,length,cs,2,array,0))
|
||||
return (1);
|
||||
if (get_interval_info(args, str_value, &interval->neg, 2, array, false))
|
||||
return true;
|
||||
interval->day= (ulong) array[0];
|
||||
interval->hour= (ulong) array[1];
|
||||
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:
|
||||
if (get_interval_info(str,length,cs,5,array,1))
|
||||
return (1);
|
||||
if (get_interval_info(args, str_value, &interval->neg, 5, array, true))
|
||||
return true;
|
||||
interval->day= (ulong) array[0];
|
||||
interval->hour= (ulong) array[1];
|
||||
interval->minute= array[2];
|
||||
interval->second= array[3];
|
||||
interval->second_part= array[4];
|
||||
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:
|
||||
if (get_interval_info(str,length,cs,4,array,1))
|
||||
return (1);
|
||||
if (get_interval_info(args, str_value, &interval->neg, 4, array, true))
|
||||
return true;
|
||||
interval->hour= (ulong) array[0];
|
||||
interval->minute= array[1];
|
||||
interval->second= array[2];
|
||||
interval->second_part= array[3];
|
||||
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:
|
||||
if (get_interval_info(str,length,cs,3,array,1))
|
||||
return (1);
|
||||
if (get_interval_info(args, str_value, &interval->neg, 3, array, true))
|
||||
return true;
|
||||
interval->minute= array[0];
|
||||
interval->second= array[1];
|
||||
interval->second_part= array[2];
|
||||
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:
|
||||
if (get_interval_info(str,length,cs,2,array,1))
|
||||
return (1);
|
||||
if (get_interval_info(args, str_value, &interval->neg, 2, array, true))
|
||||
return true;
|
||||
interval->second= array[0];
|
||||
interval->second_part= array[1];
|
||||
break;
|
||||
@ -1575,7 +1569,7 @@ bool get_interval_value(Item *args,interval_type int_type,
|
||||
DBUG_ASSERT(0);
|
||||
break; /* purecov: end */
|
||||
}
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user