Commit a60c39a2 authored by Sergey Glukhov's avatar Sergey Glukhov

Bug#11889186 60503: CRASH IN MAKE_DATE_TIME WITH DATE_FORMAT / STR_TO_DATE COMBINATION

calc_daynr() function returns negative result
if malformed date with zero year and month is used.
Attempt to calculate week day on negative value
leads to crash. The fix is return NULL for
'W', 'a', 'w' specifiers if zero year and month is used.
Additional fix for calc_daynr():
--added assertion that result can not be negative
--return 0 if zero year and month is used


mysql-test/r/func_time.result:
  test case
mysql-test/t/func_time.test:
  test case
sql-common/my_time.c:
  --added assertion that result can not be negative
  --return 0 if zero year and month is used
sql/item_timefunc.cc:
  eturn NULL for 'W', 'a', 'w' specifiers
  if zero year and month is used.
parent c575254f
...@@ -1405,4 +1405,16 @@ NULL ...@@ -1405,4 +1405,16 @@ NULL
SELECT ADDDATE(MONTH(FROM_UNIXTIME(NULL)),INTERVAL 1 HOUR); SELECT ADDDATE(MONTH(FROM_UNIXTIME(NULL)),INTERVAL 1 HOUR);
ADDDATE(MONTH(FROM_UNIXTIME(NULL)),INTERVAL 1 HOUR) ADDDATE(MONTH(FROM_UNIXTIME(NULL)),INTERVAL 1 HOUR)
NULL NULL
#
# Bug#11889186 60503: CRASH IN MAKE_DATE_TIME WITH DATE_FORMAT / STR_TO_DATE COMBINATION
#
SELECT DATE_FORMAT('0000-00-11', '%W');
DATE_FORMAT('0000-00-11', '%W')
NULL
SELECT DATE_FORMAT('0000-00-11', '%a');
DATE_FORMAT('0000-00-11', '%a')
NULL
SELECT DATE_FORMAT('0000-00-11', '%w');
DATE_FORMAT('0000-00-11', '%w')
NULL
End of 5.1 tests End of 5.1 tests
...@@ -913,4 +913,12 @@ SELECT CAST((MONTH(FROM_UNIXTIME(@@GLOBAL.SQL_MODE))) AS BINARY(1025)); ...@@ -913,4 +913,12 @@ SELECT CAST((MONTH(FROM_UNIXTIME(@@GLOBAL.SQL_MODE))) AS BINARY(1025));
SELECT ADDDATE(MONTH(FROM_UNIXTIME(NULL)),INTERVAL 1 HOUR); SELECT ADDDATE(MONTH(FROM_UNIXTIME(NULL)),INTERVAL 1 HOUR);
--echo #
--echo # Bug#11889186 60503: CRASH IN MAKE_DATE_TIME WITH DATE_FORMAT / STR_TO_DATE COMBINATION
--echo #
SELECT DATE_FORMAT('0000-00-11', '%W');
SELECT DATE_FORMAT('0000-00-11', '%a');
SELECT DATE_FORMAT('0000-00-11', '%w');
--echo End of 5.1 tests --echo End of 5.1 tests
...@@ -772,7 +772,7 @@ long calc_daynr(uint year,uint month,uint day) ...@@ -772,7 +772,7 @@ long calc_daynr(uint year,uint month,uint day)
int y= year; /* may be < 0 temporarily */ int y= year; /* may be < 0 temporarily */
DBUG_ENTER("calc_daynr"); DBUG_ENTER("calc_daynr");
if (y == 0 && month == 0 && day == 0) if (y == 0 && month == 0)
DBUG_RETURN(0); /* Skip errors */ DBUG_RETURN(0); /* Skip errors */
/* Cast to int to be able to handle month == 0 */ /* Cast to int to be able to handle month == 0 */
delsum= (long) (365 * y + 31 *((int) month - 1) + (int) day); delsum= (long) (365 * y + 31 *((int) month - 1) + (int) day);
...@@ -783,6 +783,7 @@ long calc_daynr(uint year,uint month,uint day) ...@@ -783,6 +783,7 @@ long calc_daynr(uint year,uint month,uint day)
temp=(int) ((y/100+1)*3)/4; temp=(int) ((y/100+1)*3)/4;
DBUG_PRINT("exit",("year: %d month: %d day: %d -> daynr: %ld", DBUG_PRINT("exit",("year: %d month: %d day: %d -> daynr: %ld",
y+(month <= 2),month,day,delsum+y/4-temp)); y+(month <= 2),month,day,delsum+y/4-temp));
DBUG_ASSERT(delsum+(int) y/4-temp > 0);
DBUG_RETURN(delsum+(int) y/4-temp); DBUG_RETURN(delsum+(int) y/4-temp);
} /* calc_daynr */ } /* calc_daynr */
......
...@@ -648,7 +648,7 @@ bool make_date_time(DATE_TIME_FORMAT *format, MYSQL_TIME *l_time, ...@@ -648,7 +648,7 @@ bool make_date_time(DATE_TIME_FORMAT *format, MYSQL_TIME *l_time,
system_charset_info); system_charset_info);
break; break;
case 'W': case 'W':
if (type == MYSQL_TIMESTAMP_TIME) if (type == MYSQL_TIMESTAMP_TIME || !(l_time->month || l_time->year))
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),0); l_time->day),0);
...@@ -657,7 +657,7 @@ bool make_date_time(DATE_TIME_FORMAT *format, MYSQL_TIME *l_time, ...@@ -657,7 +657,7 @@ bool make_date_time(DATE_TIME_FORMAT *format, MYSQL_TIME *l_time,
system_charset_info); system_charset_info);
break; break;
case 'a': case 'a':
if (type == MYSQL_TIMESTAMP_TIME) if (type == MYSQL_TIMESTAMP_TIME || !(l_time->month || l_time->year))
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),0); l_time->day),0);
...@@ -816,7 +816,7 @@ bool make_date_time(DATE_TIME_FORMAT *format, MYSQL_TIME *l_time, ...@@ -816,7 +816,7 @@ bool make_date_time(DATE_TIME_FORMAT *format, MYSQL_TIME *l_time,
} }
break; break;
case 'w': case 'w':
if (type == MYSQL_TIMESTAMP_TIME) if (type == MYSQL_TIMESTAMP_TIME || !(l_time->month || l_time->year))
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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment