From 459b6862272473ea9fd76d98511e9755c3ee8163 Mon Sep 17 00:00:00 2001
From: Daniel Fischer <df@sun.com>
Date: Thu, 30 Apr 2009 12:52:45 +0200
Subject: [PATCH] backport #41470, commit 62661

---
 mysql-test/r/date_formats.result | 10 ++++++++++
 mysql-test/t/date_formats.test   | 12 ++++++++++++
 sql-common/my_time.c             | 13 +++++++------
 3 files changed, 29 insertions(+), 6 deletions(-)

diff --git a/mysql-test/r/date_formats.result b/mysql-test/r/date_formats.result
index 6833a7f1594..43f656e3c99 100644
--- a/mysql-test/r/date_formats.result
+++ b/mysql-test/r/date_formats.result
@@ -593,3 +593,13 @@ select str_to_date('04/30/2004 ', '%m/%d/%Y ');
 str_to_date('04/30/2004 ', '%m/%d/%Y ')
 2004-04-30
 "End of 4.1 tests"
+SELECT DATE_FORMAT("0000-01-01",'%W %d %M %Y') as valid_date;
+valid_date
+Sunday 01 January 0000
+SELECT DATE_FORMAT("0000-02-28",'%W %d %M %Y') as valid_date;
+valid_date
+Tuesday 28 February 0000
+SELECT DATE_FORMAT("2009-01-01",'%W %d %M %Y') as valid_date;
+valid_date
+Thursday 01 January 2009
+"End of 5.0 tests"
diff --git a/mysql-test/t/date_formats.test b/mysql-test/t/date_formats.test
index faa6d4242db..0c02398acc1 100644
--- a/mysql-test/t/date_formats.test
+++ b/mysql-test/t/date_formats.test
@@ -337,3 +337,15 @@ select str_to_date('04/30 /2004', '%m /%d /%Y');
 select str_to_date('04/30/2004 ', '%m/%d/%Y ');
 
 --echo "End of 4.1 tests"
+
+#
+# Bug #41470: DATE_FORMAT() crashes the complete server with a valid date
+#
+
+# show that these two do not crash the server:
+SELECT DATE_FORMAT("0000-01-01",'%W %d %M %Y') as valid_date;
+SELECT DATE_FORMAT("0000-02-28",'%W %d %M %Y') as valid_date;
+# show that date within the Gregorian range render correct results: (THU)
+SELECT DATE_FORMAT("2009-01-01",'%W %d %M %Y') as valid_date;
+
+--echo "End of 5.0 tests"
diff --git a/sql-common/my_time.c b/sql-common/my_time.c
index 1781251fca1..16a64ebd947 100644
--- a/sql-common/my_time.c
+++ b/sql-common/my_time.c
@@ -765,19 +765,20 @@ long calc_daynr(uint year,uint month,uint day)
 {
   long delsum;
   int temp;
+  int y= year;                                  /* may be < 0 temporarily */
   DBUG_ENTER("calc_daynr");
 
-  if (year == 0 && month == 0 && day == 0)
+  if (y == 0 && month == 0 && day == 0)
     DBUG_RETURN(0);				/* Skip errors */
-  delsum= (long) (365L * year+ 31*(month-1) +day);
+  delsum= (long) (365L * y+ 31*(month-1) +day);
   if (month <= 2)
-      year--;
+      y--;
   else
     delsum-= (long) (month*4+23)/10;
-  temp=(int) ((year/100+1)*3)/4;
+  temp=(int) ((y/100+1)*3)/4;
   DBUG_PRINT("exit",("year: %d  month: %d  day: %d -> daynr: %ld",
-		     year+(month <= 2),month,day,delsum+year/4-temp));
-  DBUG_RETURN(delsum+(int) year/4-temp);
+		     y+(month <= 2),month,day,delsum+y/4-temp));
+  DBUG_RETURN(delsum+(int) y/4-temp);
 } /* calc_daynr */