List:Commits« Previous MessageNext Message »
From:Alexander Barkov Date:November 18 2011 1:27pm
Subject:bzr push into mysql-trunk branch (alexander.barkov:3599 to 3600)
View as plain text  
 3600 Alexander Barkov	2011-11-18 [merge]
      Merging latest bug fixes from mysql-trunk-wl946

    modified:
      mysql-test/r/timezone2.result
      mysql-test/r/type_temporal_fractional.result
      mysql-test/t/timezone2.test
      mysql-test/t/type_temporal_fractional.test
      sql/field.cc
      sql/field.h
      sql/item.cc
      sql/item.h
      sql/item_cmpfunc.cc
      sql/item_timefunc.cc
      sql/sql_time.cc
      sql/sql_time.h
      unittest/gunit/field-t.cc
 3599 Mayank Prasad	2011-11-18
      WL#5885 
      
      details:
      - Added test case for IS_ROUTINES/PARAMETERS tables
        to test DATETIME PRECISION for values 1-6.

    modified:
      mysql-test/r/information_schema_parameters.result
      mysql-test/r/information_schema_routines.result
      mysql-test/t/information_schema_parameters.test
      mysql-test/t/information_schema_routines.test
=== modified file 'mysql-test/r/timezone2.result'
--- a/mysql-test/r/timezone2.result	2010-08-06 19:29:37 +0000
+++ b/mysql-test/r/timezone2.result	2011-11-18 09:52:00 +0000
@@ -309,3 +309,33 @@ CONVERT_TZ(1, 1, a)
 NULL
 DROP TABLE t1;
 End of 5.1 tests
+#
+# Start of 5.6 tests
+#
+SET time_zone='Europe/Moscow';
+CREATE TABLE t1 (a TIMESTAMP, b VARCHAR(30));
+INSERT INTO t1 VALUES
+('2003-03-30 01:59:59', 'Before the gap'),
+('2003-03-30 02:30:00', 'Inside the gap'),
+('2003-03-30 03:00:00',  'After the gap');
+Warnings:
+Warning	1299	Invalid TIMESTAMP value in column 'a' at row 2
+SELECT a, UNIX_TIMESTAMP(a), b FROM t1;
+a	UNIX_TIMESTAMP(a)	b
+2003-03-30 01:59:59	1048978799	Before the gap
+2003-03-30 03:00:00	1048978800	Inside the gap
+2003-03-30 03:00:00	1048978800	After the gap
+DROP TABLE t1;
+SELECT UNIX_TIMESTAMP('2003-03-30 01:59:59'), 'Before the gap' AS b;
+UNIX_TIMESTAMP('2003-03-30 01:59:59')	b
+1048978799	Before the gap
+SELECT UNIX_TIMESTAMP('2003-03-30 02:30:00'), 'Inside the gap' AS b;
+UNIX_TIMESTAMP('2003-03-30 02:30:00')	b
+1048978800	Inside the gap
+SELECT UNIX_TIMESTAMP('2003-03-30 03:00:00'), 'After the gap' AS b;
+UNIX_TIMESTAMP('2003-03-30 03:00:00')	b
+1048978800	After the gap
+SET time_zone=DEFAULT;
+#
+# End of 5.6 tests
+#

=== modified file 'mysql-test/r/type_temporal_fractional.result'
--- a/mysql-test/r/type_temporal_fractional.result	2011-11-17 13:41:28 +0000
+++ b/mysql-test/r/type_temporal_fractional.result	2011-11-18 13:26:35 +0000
@@ -16647,3 +16647,151 @@ Warning	1292	Truncated incorrect time va
 Warning	1292	Truncated incorrect time value: '2002-11-24'
 DROP VIEW v1;
 DROP TABLE t1;
+#
+# Bug#13401354 ITEM->FIELD_TYPE() == MYSQL_TYPE_TIME || ITEM->FIELD_TYPE() == MYSQL_TYPE_NULL
+#
+CREATE TABLE t1 (col_time_not_null TIME NOT NULL);
+SELECT * FROM t1
+WHERE  col_time_not_null = DATE(NULL) AND col_time_not_null = TIME(NULL);
+col_time_not_null
+DROP TABLE t1;
+CREATE TABLE t1 (
+col_date DATE,
+col_time_not_null TIME not null,
+pk TIMESTAMP(6),
+col_timestamp_3_not_null_key TIMESTAMP(3) NOT NULL,
+col_date_not_null DATE NOT NULL,
+col_time_3_key TIME(3),
+col_timestamp_6_key TIMESTAMP(6) NOT NULL,
+col_datetime DATETIME,
+col_datetime_6 DATETIME(6),
+col_timestamp_3_key TIMESTAMP(3) NOT NULL,
+col_time_6_not_null TIME(6) NOT NULL,
+col_time_6 TIME(6),
+col_time_6_not_null_key TIME(6) NOT NULL,
+col_datetime_not_null DATETIME NOT NULL,
+col_datetime_3_not_null_key DATETIME(3) NOT NULL,
+KEY (col_datetime_3_not_null_key));
+SELECT col_time_6 AS c1, NOW() AS c2 FROM t1
+WHERE
+col_datetime_not_null BETWEEN SUBTIME('0000-00-00','00:00:00') AND col_date_not_null
+AND
+col_time_not_null=STR_TO_DATE(DATE_FORMAT(TIME('00:00:00.000000'),CONCAT_WS('-','%s','%k' )),CONCAT_WS(':','%i','%M'))
+AND
+col_date BETWEEN UNIX_TIMESTAMP('0000-00-00 00:00:00') AND col_timestamp_3_key
+AND
+col_datetime_6 NOT IN (col_time_6_not_null,'0000-00-00')
+AND
+col_time_not_null = TIMEDIFF(CURDATE(),'00:00:00.000000')
+AND
+col_time_3_key NOT IN (col_timestamp_6_key,pk)
+AND
+col_timestamp_3_not_null_key < col_datetime;
+c1	c2
+Warnings:
+Warning	1411	Incorrect datetime value: '00-0' for function str_to_date
+Warning	1411	Incorrect datetime value: '00-0' for function str_to_date
+DROP TABLE t1;
+#
+# Bug#13399082 - ASSERTION `MON > 0 && MON < 13' FAILED IN TZTIME.CC | SEC_SINCE_EPOCH
+#
+SET TIME_ZONE='+02:00';
+SELECT UNIX_TIMESTAMP(STR_TO_DATE('2020','%Y'));
+UNIX_TIMESTAMP(STR_TO_DATE('2020','%Y'))
+0
+SET TIME_ZONE=DEFAULT;
+# This should return NULL
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES(NULL);
+SELECT UNIX_TIMESTAMP(a) FROM t1;
+UNIX_TIMESTAMP(a)
+NULL
+DROP TABLE t1;
+SELECT UNIX_TIMESTAMP(NULL);
+UNIX_TIMESTAMP(NULL)
+NULL
+SELECT UNIX_TIMESTAMP(DATE(NULL));
+UNIX_TIMESTAMP(DATE(NULL))
+NULL
+SELECT UNIX_TIMESTAMP(TIME(NULL));
+UNIX_TIMESTAMP(TIME(NULL))
+NULL
+SELECT UNIX_TIMESTAMP(TIMESTAMP(NULL));
+UNIX_TIMESTAMP(TIMESTAMP(NULL))
+NULL
+# This should return 0
+CREATE TABLE t1 (a VARCHAR(30));
+INSERT INTO t1 VALUES
+('0000-01-01 00:00:00'),('2001-00-01 00:00:01'),('2001-01-00 00:00:00'),
+('0000-00-00 00:00:01'),('0000-00-00 00:00:00.1');
+SELECT UNIX_TIMESTAMP(a) FROM t1;
+UNIX_TIMESTAMP(a)
+0.000000
+0.000000
+0.000000
+0.000000
+0.000000
+DROP TABLE t1;
+SELECT UNIX_TIMESTAMP('0000-01-01 00:00:00');
+UNIX_TIMESTAMP('0000-01-01 00:00:00')
+0
+SELECT UNIX_TIMESTAMP('2001-00-01 00:00:00');
+UNIX_TIMESTAMP('2001-00-01 00:00:00')
+0
+SELECT UNIX_TIMESTAMP('2001-01-00 00:00:00');
+UNIX_TIMESTAMP('2001-01-00 00:00:00')
+0
+SELECT UNIX_TIMESTAMP('0000-00-00 10:10:20');
+UNIX_TIMESTAMP('0000-00-00 10:10:20')
+0
+SELECT UNIX_TIMESTAMP('0000-00-00 00:00:00.1');
+UNIX_TIMESTAMP('0000-00-00 00:00:00.1')
+0.0
+SELECT UNIX_TIMESTAMP(TIMESTAMP'0000-00-00 10:10:20');
+UNIX_TIMESTAMP(TIMESTAMP'0000-00-00 10:10:20')
+0
+SELECT UNIX_TIMESTAMP(TIMESTAMP'0000-00-00 00:00:00.1');
+UNIX_TIMESTAMP(TIMESTAMP'0000-00-00 00:00:00.1')
+0.0
+SELECT UNIX_TIMESTAMP(TIMESTAMP('0000-00-00 10:10:20'));
+UNIX_TIMESTAMP(TIMESTAMP('0000-00-00 10:10:20'))
+0
+SELECT UNIX_TIMESTAMP(TIMESTAMP('0000-00-00 00:00:00.1'));
+UNIX_TIMESTAMP(TIMESTAMP('0000-00-00 00:00:00.1'))
+0.0
+#
+# Bug#13354387 - CRASH IN IN MY_DECIMAL::OPERATOR FOR VIEW AND FUNCTION UNIX_TIMESTAMP
+#
+SET timestamp=UNIX_TIMESTAMP('2011-11-18 14:36:00');
+CREATE TABLE t1 (
+pk time(2) NOT NULL DEFAULT '00:00:00.00',  
+col_timestamp_3_not_null timestamp(3) NULL DEFAULT '0000-00-00 00:00:00.000',
+col_datetime_1_key datetime(1) DEFAULT NULL,
+col_datetime_6_not_null_key datetime(6) NOT NULL,
+col_datetime_2_not_null datetime(2) NOT NULL,
+PRIMARY KEY (pk),
+KEY col_datetime_1_key (col_datetime_1_key),
+KEY col_datetime_6_not_null_key (col_datetime_6_not_null_key))
+ENGINE=MyISAM DEFAULT CHARSET=latin1;
+INSERT INTO t1 VALUES ('19:14:35.36','0000-00-00 00:00:00.000','0000-00-00 00:00:00.0','2000-08-28 07:34:20.051690','2009-09-20 07:32:39.06');
+INSERT INTO t1 VALUES ('19:14:37.36','2005-07-04 08:03:50.051','0000-00-00 00:00:00.0','0000-00-00 00:00:00.000000','0000-00-00 00:00:00.00');
+INSERT INTO t1 VALUES ('19:14:39.36','0000-00-00 00:00:00.000',NULL,'2005-10-11 07:24:45.059064','2009-11-19 00:00:00.00');
+INSERT INTO t1 VALUES ('19:14:41.36','2005-11-22 21:00:00.000',NULL,'0000-00-00 00:00:00.000000','0000-00-00 00:00:00.00');
+INSERT INTO t1 VALUES ('19:14:43.36','2009-11-06 21:00:00.000','2007-07-03 11:13:08.0','2002-09-02 00:17:37.037583','2003-09-25 09:29:41.00');
+INSERT INTO t1 VALUES ('19:14:36.36','2009-08-15 05:43:18.029','2009-01-18 00:00:00.0','0000-00-00 00:00:00.000000','2007-07-20 08:31:37.02');
+INSERT INTO t1 VALUES ('19:14:38.36','0000-00-00 00:00:00.000','0000-00-00 00:00:00.0','0000-00-00 00:00:00.000000','2004-08-16 05:11:47.04');
+INSERT INTO t1 VALUES ('19:14:40.36','2000-04-16 21:00:00.000',NULL,'2004-04-27 00:00:00.000000','2009-06-03 00:18:49.04');
+INSERT INTO t1 VALUES ('19:14:42.36','2009-01-18 20:46:41.035','2003-03-23 11:37:04.0','0000-00-00 00:00:00.000000','2009-12-26 00:00:00.00');
+INSERT INTO t1 VALUES ('19:14:44.36','0000-00-00 00:00:00.000','0000-00-00 00:00:00.0','2005-09-14 15:13:53.062460','0000-00-00 00:00:00.00');
+CREATE OR REPLACE VIEW v1 AS SELECT * FROM t1;
+SELECT UNIX_TIMESTAMP(col_datetime_2_not_null) AS c1
+FROM  v1
+WHERE col_datetime_6_not_null_key > col_datetime_1_key
+AND col_timestamp_3_not_null IS NOT NULL
+ORDER BY 1;
+c1
+0.00
+1253421159.06
+DROP VIEW v1;
+DROP TABLE t1;
+SET timestamp=DEFAULT;

=== modified file 'mysql-test/t/timezone2.test'
--- a/mysql-test/t/timezone2.test	2010-08-06 19:29:37 +0000
+++ b/mysql-test/t/timezone2.test	2011-11-18 09:52:00 +0000
@@ -284,3 +284,25 @@ SELECT CONVERT_TZ(1, 1, a) FROM t1;
 DROP TABLE t1;
 
 --echo End of 5.1 tests
+
+--echo #
+--echo # Start of 5.6 tests
+--echo #
+SET time_zone='Europe/Moscow';
+CREATE TABLE t1 (a TIMESTAMP, b VARCHAR(30));
+# Testing values around winter/summer time change
+# Expect non-zero UNIX_TIMESTAMP value for all of them
+INSERT INTO t1 VALUES
+('2003-03-30 01:59:59', 'Before the gap'),
+('2003-03-30 02:30:00', 'Inside the gap'),
+('2003-03-30 03:00:00',  'After the gap');
+SELECT a, UNIX_TIMESTAMP(a), b FROM t1;
+DROP TABLE t1;
+SELECT UNIX_TIMESTAMP('2003-03-30 01:59:59'), 'Before the gap' AS b;
+SELECT UNIX_TIMESTAMP('2003-03-30 02:30:00'), 'Inside the gap' AS b;
+SELECT UNIX_TIMESTAMP('2003-03-30 03:00:00'), 'After the gap' AS b;
+SET time_zone=DEFAULT;
+
+--echo #
+--echo # End of 5.6 tests
+--echo #

=== modified file 'mysql-test/t/type_temporal_fractional.test'
--- a/mysql-test/t/type_temporal_fractional.test	2011-11-17 13:41:28 +0000
+++ b/mysql-test/t/type_temporal_fractional.test	2011-11-18 13:26:35 +0000
@@ -7220,6 +7220,118 @@ DROP VIEW v1;
 DROP TABLE t1;
 
 
+--echo #
+--echo # Bug#13401354 ITEM->FIELD_TYPE() == MYSQL_TYPE_TIME || ITEM->FIELD_TYPE() == MYSQL_TYPE_NULL
+--echo #
+CREATE TABLE t1 (col_time_not_null TIME NOT NULL);
+SELECT * FROM t1
+WHERE  col_time_not_null = DATE(NULL) AND col_time_not_null = TIME(NULL);
+DROP TABLE t1;
+CREATE TABLE t1 (
+  col_date DATE,
+  col_time_not_null TIME not null,
+  pk TIMESTAMP(6),
+  col_timestamp_3_not_null_key TIMESTAMP(3) NOT NULL,
+  col_date_not_null DATE NOT NULL,
+  col_time_3_key TIME(3),
+  col_timestamp_6_key TIMESTAMP(6) NOT NULL,
+  col_datetime DATETIME,
+  col_datetime_6 DATETIME(6),
+  col_timestamp_3_key TIMESTAMP(3) NOT NULL,
+  col_time_6_not_null TIME(6) NOT NULL,
+  col_time_6 TIME(6),
+  col_time_6_not_null_key TIME(6) NOT NULL,
+  col_datetime_not_null DATETIME NOT NULL,
+  col_datetime_3_not_null_key DATETIME(3) NOT NULL,
+  KEY (col_datetime_3_not_null_key));
+SELECT col_time_6 AS c1, NOW() AS c2 FROM t1
+WHERE
+  col_datetime_not_null BETWEEN SUBTIME('0000-00-00','00:00:00') AND col_date_not_null
+AND
+  col_time_not_null=STR_TO_DATE(DATE_FORMAT(TIME('00:00:00.000000'),CONCAT_WS('-','%s','%k' )),CONCAT_WS(':','%i','%M'))
+AND
+  col_date BETWEEN UNIX_TIMESTAMP('0000-00-00 00:00:00') AND col_timestamp_3_key
+AND
+  col_datetime_6 NOT IN (col_time_6_not_null,'0000-00-00')
+AND
+  col_time_not_null = TIMEDIFF(CURDATE(),'00:00:00.000000')
+AND
+  col_time_3_key NOT IN (col_timestamp_6_key,pk)
+AND
+  col_timestamp_3_not_null_key < col_datetime; 
+DROP TABLE t1;
+
+
+--echo #
+--echo # Bug#13399082 - ASSERTION `MON > 0 && MON < 13' FAILED IN TZTIME.CC | SEC_SINCE_EPOCH
+--echo #
+SET TIME_ZONE='+02:00';
+SELECT UNIX_TIMESTAMP(STR_TO_DATE('2020','%Y'));
+SET TIME_ZONE=DEFAULT;
+
+--echo # This should return NULL
+CREATE TABLE t1 (a INT);
+INSERT INTO t1 VALUES(NULL);
+SELECT UNIX_TIMESTAMP(a) FROM t1;
+DROP TABLE t1;
+SELECT UNIX_TIMESTAMP(NULL);
+SELECT UNIX_TIMESTAMP(DATE(NULL));
+SELECT UNIX_TIMESTAMP(TIME(NULL));
+SELECT UNIX_TIMESTAMP(TIMESTAMP(NULL));
+
+--echo # This should return 0
+CREATE TABLE t1 (a VARCHAR(30));
+INSERT INTO t1 VALUES
+('0000-01-01 00:00:00'),('2001-00-01 00:00:01'),('2001-01-00 00:00:00'),
+('0000-00-00 00:00:01'),('0000-00-00 00:00:00.1');
+SELECT UNIX_TIMESTAMP(a) FROM t1;
+DROP TABLE t1;
+SELECT UNIX_TIMESTAMP('0000-01-01 00:00:00');
+SELECT UNIX_TIMESTAMP('2001-00-01 00:00:00');
+SELECT UNIX_TIMESTAMP('2001-01-00 00:00:00');
+SELECT UNIX_TIMESTAMP('0000-00-00 10:10:20');
+SELECT UNIX_TIMESTAMP('0000-00-00 00:00:00.1');
+SELECT UNIX_TIMESTAMP(TIMESTAMP'0000-00-00 10:10:20');
+SELECT UNIX_TIMESTAMP(TIMESTAMP'0000-00-00 00:00:00.1');
+SELECT UNIX_TIMESTAMP(TIMESTAMP('0000-00-00 10:10:20'));
+SELECT UNIX_TIMESTAMP(TIMESTAMP('0000-00-00 00:00:00.1'));
+
+
+--echo #
+--echo # Bug#13354387 - CRASH IN IN MY_DECIMAL::OPERATOR FOR VIEW AND FUNCTION UNIX_TIMESTAMP
+--echo #
+SET timestamp=UNIX_TIMESTAMP('2011-11-18 14:36:00');
+CREATE TABLE t1 (
+  pk time(2) NOT NULL DEFAULT '00:00:00.00',  
+  col_timestamp_3_not_null timestamp(3) NULL DEFAULT '0000-00-00 00:00:00.000',
+  col_datetime_1_key datetime(1) DEFAULT NULL,
+  col_datetime_6_not_null_key datetime(6) NOT NULL,
+  col_datetime_2_not_null datetime(2) NOT NULL,
+  PRIMARY KEY (pk),
+  KEY col_datetime_1_key (col_datetime_1_key),
+  KEY col_datetime_6_not_null_key (col_datetime_6_not_null_key))
+ENGINE=MyISAM DEFAULT CHARSET=latin1;
+INSERT INTO t1 VALUES ('19:14:35.36','0000-00-00 00:00:00.000','0000-00-00 00:00:00.0','2000-08-28 07:34:20.051690','2009-09-20 07:32:39.06');
+INSERT INTO t1 VALUES ('19:14:37.36','2005-07-04 08:03:50.051','0000-00-00 00:00:00.0','0000-00-00 00:00:00.000000','0000-00-00 00:00:00.00');
+INSERT INTO t1 VALUES ('19:14:39.36','0000-00-00 00:00:00.000',NULL,'2005-10-11 07:24:45.059064','2009-11-19 00:00:00.00');
+INSERT INTO t1 VALUES ('19:14:41.36','2005-11-22 21:00:00.000',NULL,'0000-00-00 00:00:00.000000','0000-00-00 00:00:00.00');
+INSERT INTO t1 VALUES ('19:14:43.36','2009-11-06 21:00:00.000','2007-07-03 11:13:08.0','2002-09-02 00:17:37.037583','2003-09-25 09:29:41.00');
+INSERT INTO t1 VALUES ('19:14:36.36','2009-08-15 05:43:18.029','2009-01-18 00:00:00.0','0000-00-00 00:00:00.000000','2007-07-20 08:31:37.02');
+INSERT INTO t1 VALUES ('19:14:38.36','0000-00-00 00:00:00.000','0000-00-00 00:00:00.0','0000-00-00 00:00:00.000000','2004-08-16 05:11:47.04');
+INSERT INTO t1 VALUES ('19:14:40.36','2000-04-16 21:00:00.000',NULL,'2004-04-27 00:00:00.000000','2009-06-03 00:18:49.04');
+INSERT INTO t1 VALUES ('19:14:42.36','2009-01-18 20:46:41.035','2003-03-23 11:37:04.0','0000-00-00 00:00:00.000000','2009-12-26 00:00:00.00');
+INSERT INTO t1 VALUES ('19:14:44.36','0000-00-00 00:00:00.000','0000-00-00 00:00:00.0','2005-09-14 15:13:53.062460','0000-00-00 00:00:00.00');
+CREATE OR REPLACE VIEW v1 AS SELECT * FROM t1;
+SELECT UNIX_TIMESTAMP(col_datetime_2_not_null) AS c1
+FROM  v1
+WHERE col_datetime_6_not_null_key > col_datetime_1_key
+AND col_timestamp_3_not_null IS NOT NULL
+ORDER BY 1;
+DROP VIEW v1;
+DROP TABLE t1;
+SET timestamp=DEFAULT;
+
+
 ## TS-TODO: SELECT CAST('00:00:00' AS DATETIME) -> should it use curdate?
 
 ## TS-TODO: reuse count_datetime_length()/count_string_result_length()

=== modified file 'sql/field.cc'
--- a/sql/field.cc	2011-11-17 13:41:28 +0000
+++ b/sql/field.cc	2011-11-18 13:26:35 +0000
@@ -1797,15 +1797,12 @@ bool Field::get_time(MYSQL_TIME *ltime)
 }
 
 
-bool Field::get_timestamp(struct timeval *tm)
+bool Field::get_timestamp(struct timeval *tm, int *warnings)
 {
   MYSQL_TIME ltime;
-  if (get_date(&ltime, TIME_FUZZY_DATE))
-    return true;
-  my_bool not_used;
-  tm->tv_sec= TIME_to_timestamp(current_thd, &ltime, &not_used);
-  tm->tv_usec= ltime.second_part;
-  return false;
+  DBUG_ASSERT(!is_null());
+  return get_date(&ltime, TIME_FUZZY_DATE) ||
+         datetime_to_timeval(current_thd, &ltime, tm, warnings);
 }
 
 
@@ -5159,30 +5156,14 @@ Field_temporal_with_date_and_time::conve
                                                              struct timeval *tm,
                                                              int *warnings)
 {
-  my_bool in_dst_time_gap;
-  /* Only convert a correct date (not a zero date) */
-  if (!ltime->month)
+  /*
+    No needs to do check_date(TIME_NO_ZERO_IN_DATE),
+    because it has been done earlier in
+    store_time(), number_to_datetime() or str_to_datetime().
+  */
+  if (datetime_with_no_zero_in_date_to_timeval(thd, ltime, tm, warnings))
   {
     tm->tv_sec= tm->tv_usec= 0;
-    if (ltime->second_part)
-    {
-      /* Don't allow zero timestamp with microseconds */
-      *warnings|= MYSQL_TIME_WARN_TRUNCATED;
-      return true;    
-    }
-    return false;
-  }
-
-  tm->tv_usec= ltime->second_part;
-
-  if (!(tm->tv_sec= TIME_to_timestamp(thd, ltime, &in_dst_time_gap)))
-  {
-    *warnings|= MYSQL_TIME_WARN_OUT_OF_RANGE;
-    return true;    
-  }
-  else if (in_dst_time_gap)
-  {
-    *warnings|= MYSQL_TIME_WARN_INVALID_TIMESTAMP;
     return true;
   }
   return false;
@@ -5361,7 +5342,7 @@ bool Field_timestamp::get_date_internal(
 /**
    Get TIMESTAMP field value as seconds since begging of Unix Epoch
 */
-bool Field_timestamp::get_timestamp(struct timeval *tm)
+bool Field_timestamp::get_timestamp(struct timeval *tm, int *warnings)
 {
   if (is_null())
     return true;
@@ -5570,12 +5551,11 @@ Field_timestampf::get_date_internal(MYSQ
 }
 
 
-bool Field_timestampf::get_timestamp(struct timeval *tm)
+bool Field_timestampf::get_timestamp(struct timeval *tm, int *warnings)
 {
   THD *thd= table ? table->in_use : current_thd;
   thd->time_zone_used= 1;
-  if (is_null())
-    return true;
+  DBUG_ASSERT(!is_null());
   my_timestamp_from_binary(tm, ptr, dec);
   return false;
 }

=== modified file 'sql/field.h'
--- a/sql/field.h	2011-11-17 13:41:28 +0000
+++ b/sql/field.h	2011-11-18 13:26:35 +0000
@@ -539,7 +539,7 @@ public:
     This method is used in "SELECT UNIX_TIMESTAMP(field)"
     to avoid conversion from timestamp to MYSQL_TIME and back.
   */
-  virtual bool get_timestamp(struct timeval *tm);
+  virtual bool get_timestamp(struct timeval *tm, int *warnings);
   /**
     Stores a timestamp value in "struct timeval" format into a field.
     Note, store_timestamp(), get_timestamp() and store_time()
@@ -2174,7 +2174,7 @@ public:
       Field::set_default();
   }
   /* Get TIMESTAMP field value as seconds since begging of Unix Epoch */
-  bool get_timestamp(struct timeval *tm);
+  bool get_timestamp(struct timeval *tm, int *warnings);
   bool get_date(MYSQL_TIME *ltime,uint fuzzydate);
   Field_timestamp *clone(MEM_ROOT *mem_root) const {
     DBUG_ASSERT(type() == MYSQL_TYPE_TIMESTAMP);
@@ -2269,7 +2269,7 @@ public:
     else
       Field::set_default();
   }
-  bool get_timestamp(struct timeval *tm);
+  bool get_timestamp(struct timeval *tm, int *warnings);
 };
 
 

=== modified file 'sql/item.cc'
--- a/sql/item.cc	2011-11-17 13:41:28 +0000
+++ b/sql/item.cc	2011-11-18 13:26:35 +0000
@@ -1375,17 +1375,14 @@ bool Item::get_time_from_non_temporal(MY
   }
   return (null_value= true); // Impossible result type
 }
- 
 
-bool Item::get_timeval(struct timeval *tm)
+
+bool Item::get_timeval(struct timeval *tm, int *warnings)
 {
   MYSQL_TIME ltime;
-  if (get_date(&ltime, 0))
-    return true;
-  my_bool not_used;
-  tm->tv_sec= TIME_to_timestamp(current_thd, &ltime, &not_used);
-  tm->tv_usec= ltime.second_part;
-  return false;
+  return (null_value=
+          (get_date(&ltime, TIME_FUZZY_DATE) ||
+           datetime_to_timeval(current_thd, &ltime, tm, warnings)));
 }
 
 
@@ -2677,9 +2674,10 @@ bool Item_field::get_time(MYSQL_TIME *lt
   return 0;
 }
 
-bool Item_field::get_timeval(struct timeval *tm)
+bool Item_field::get_timeval(struct timeval *tm, int *warnings)
 {
-  return ((null_value= field->get_timestamp(tm)));
+  return (null_value= (field->is_null() ||
+                       field->get_timestamp(tm, warnings)));
 }
 
 double Item_field::val_result()

=== modified file 'sql/item.h'
--- a/sql/item.h	2011-11-10 14:58:23 +0000
+++ b/sql/item.h	2011-11-18 09:52:00 +0000
@@ -1082,7 +1082,7 @@ public:
     @retval  false on success
     @retval  true  on error
   */
-  virtual bool get_timeval(struct timeval *tm);
+  virtual bool get_timeval(struct timeval *tm, int *warnings);
   virtual bool get_date_result(MYSQL_TIME *ltime,uint fuzzydate)
   { return get_date(ltime,fuzzydate); }
   /*
@@ -1989,7 +1989,7 @@ public:
   bool get_date(MYSQL_TIME *ltime,uint fuzzydate);
   bool get_date_result(MYSQL_TIME *ltime,uint fuzzydate);
   bool get_time(MYSQL_TIME *ltime);
-  bool get_timeval(struct timeval *tm);
+  bool get_timeval(struct timeval *tm, int *warnings);
   bool is_null() { return field->is_null(); }
   void update_null_value();
   Item *get_tmp_table_item(THD *thd);

=== modified file 'sql/item_cmpfunc.cc'
--- a/sql/item_cmpfunc.cc	2011-11-17 13:41:28 +0000
+++ b/sql/item_cmpfunc.cc	2011-11-18 13:26:35 +0000
@@ -910,8 +910,32 @@ get_time_value(THD *thd, Item ***item_ar
   longlong value;
   Item *item= **item_arg;
 
+  /*
+    Note, it's wrong to assume that we always get
+    a TIME expression or NULL here:
+
   DBUG_ASSERT(item->field_type() == MYSQL_TYPE_TIME || 
               item->field_type() == MYSQL_TYPE_NULL);
+
+    because when this condition is optimized:
+
+    WHERE time_column=DATE(NULL) AND time_column=TIME(NULL);
+
+    rhe first AND part is eliminated and DATE(NULL) is substituted
+    to the second AND part like this:
+
+    WHERE DATE(NULL) = TIME(NULL) // as TIME
+
+    whose Arg_comparator has already get_time_value set for both arguments.
+    Therefore, get_time_value is executed for DATE(NULL).
+    This condition is further evaluated as impossible condition.
+
+    TS-TODO: perhaps such cases should be evaluated without
+    calling get_time_value at all.
+
+    See a similar comment in Arg_comparator::compare_temporal_packed,
+    for DATETIME comparison.
+  */
   value= item->val_time_temporal();
   *is_null= item->null_value;
 

=== modified file 'sql/item_timefunc.cc'
--- a/sql/item_timefunc.cc	2011-11-17 13:41:28 +0000
+++ b/sql/item_timefunc.cc	2011-11-18 13:26:35 +0000
@@ -1474,14 +1474,19 @@ bool Item_func_unix_timestamp::val_timev
     tm->tv_usec= 0;
     return false; // no args: null_value is set in constructor and is always 0.
   }
-  if (args[0]->get_timeval(tm)) // Don't set null_value here
+  int warnings= 0;
+  if (args[0]->get_timeval(tm, &warnings)) // Don't set null_value here
   {
-    tm->tv_sec= tm->tv_usec= 0;
     /*
-      We set null_value only if args[0] returned null.
+      We set null_value only if args[0]->get_date() invoked
+      inside args[0]->get_timeval() returned null,
+      which is indicated by "warnings == 0".
       In case of wrong non-null datetime parameter we return 0.
+      "warnings" will not be equal to 0 in this case.
     */
-    return (null_value= args[0]->null_value);
+    if (warnings == 0)
+      return (null_value= true);
+    tm->tv_sec= tm->tv_usec= 0;
   }
   return (null_value= false);
 }
@@ -1502,10 +1507,9 @@ longlong Item_func_unix_timestamp::val_i
   DBUG_ASSERT(arg_count == 1 &&
               args[0]->type() == Item::FIELD_ITEM &&
               args[0]->field_type() == MYSQL_TYPE_TIMESTAMP);
-  Field *field=((Item_field*) args[0])->field;
   /* Leave the incl_endp intact */
   struct timeval tm;
-  return (null_value= field->get_timestamp(&tm)) ? 0 : tm.tv_sec;
+  return val_timeval(&tm) ?  0 : tm.tv_sec;
 }
 
 

=== modified file 'sql/sql_time.cc'
--- a/sql/sql_time.cc	2011-11-03 09:33:45 +0000
+++ b/sql/sql_time.cc	2011-11-18 09:52:00 +0000
@@ -637,6 +637,116 @@ my_time_t TIME_to_timestamp(THD *thd, co
 }
 
 
+/**
+  Convert a datetime MYSQL_TIME representation
+  to corresponding "struct timeval" value.
+
+  ltime must previously be checked for TIME_NO_ZERO_IN_DATE.
+  Things like '0000-01-01', '2000-00-01', '2000-01-00' are not allowed
+  and asserted.
+
+  Things like '0000-00-00 10:30:30' or '0000-00-00 00:00:00.123456'
+  (i.e. empty date with non-empty time) return error.
+
+  Zero datetime '0000-00-00 00:00:00.000000'
+  is allowed and is mapper to {tv_sec=0, tv_usec=0}.
+
+  Note: In case of error, tm value is not initialized.
+
+  Note: "warnings" is not initialized to zero,
+  so new warnings are added to the old ones.
+  Caller must make sure to initialize "warnings".
+
+  @param IN  thd       current thd
+  @param IN  ltime     datetime value
+  @param OUT tm        timeval value
+  @param OUT warnings  pointer to warnings vector
+  @return
+  @retval      false on success
+  @retval      true on error
+*/
+bool datetime_with_no_zero_in_date_to_timeval(THD *thd,
+                                              const MYSQL_TIME *ltime,
+                                              struct timeval *tm,
+                                              int *warnings)
+{
+  if (!ltime->month) /* Zero date */
+  {
+    DBUG_ASSERT(!ltime->year && !ltime->day);
+    if (non_zero_time(ltime))
+    {
+      /*
+        Return error for zero date with non-zero time, e.g.:
+        '0000-00-00 10:20:30' or '0000-00-00 00:00:00.123456'
+      */
+      *warnings|= MYSQL_TIME_WARN_TRUNCATED;
+      return true;
+    }
+    tm->tv_sec= tm->tv_usec= 0; // '0000-00-00 00:00:00.000000'
+    return false;
+  }
+
+  my_bool in_dst_time_gap;
+  if (!(tm->tv_sec= TIME_to_timestamp(current_thd, ltime, &in_dst_time_gap)))
+  {
+    /*
+      Date was outside of the supported timestamp range.
+      For example: '3001-01-01 00:00:00' or '1000-01-01 00:00:00'
+    */
+    *warnings|= MYSQL_TIME_WARN_OUT_OF_RANGE;
+    return true;
+  }
+  else if (in_dst_time_gap)
+  {
+    /*
+      Set MYSQL_TIME_WARN_INVALID_TIMESTAMP warning to indicate
+      that date was fine but pointed to winter/summer time switch gap.
+      In this case tm is set to the fist second after gap.
+      For example: '2003-03-30 02:30:00 MSK' -> '2003-03-30 03:00:00 MSK'
+    */
+    *warnings|= MYSQL_TIME_WARN_INVALID_TIMESTAMP;
+  }
+  tm->tv_usec= ltime->second_part;
+  return false;
+}
+
+
+/**
+  Convert a datetime MYSQL_TIME representation
+  to corresponding "struct timeval" value.
+
+  Things like '0000-01-01', '2000-00-01', '2000-01-00'
+  (i.e. incomplete date) return error.
+
+  Things like '0000-00-00 10:30:30' or '0000-00-00 00:00:00.123456'
+  (i.e. empty date with non-empty time) return error.
+
+  Zero datetime '0000-00-00 00:00:00.000000'
+  is allowed and is mapper to {tv_sec=0, tv_usec=0}.
+
+  Note: In case of error, tm value is not initialized.
+
+  Note: "warnings" is not initialized to zero,
+  so new warnings are added to the old ones.
+  Caller must make sure to initialize "warnings".
+
+  @param IN  thd       current thd
+  @param IN  ltime     datetime value
+  @param OUT tm        timeval value
+  @param OUT warnings  pointer to warnings vector
+  @return
+  @retval      false on success
+  @retval      true on error
+*/
+bool datetime_to_timeval(THD *thd, const MYSQL_TIME *ltime,
+                         struct timeval *tm, int *warnings)
+{
+  return
+    check_date(ltime, non_zero_date(ltime), TIME_NO_ZERO_IN_DATE, warnings) ||
+    datetime_with_no_zero_in_date_to_timeval(current_thd, ltime, tm, warnings);
+}
+
+
 /*
   Convert a time string to a MYSQL_TIME struct and produce a warning
   if string was cut during conversion.

=== modified file 'sql/sql_time.h'
--- a/sql/sql_time.h	2011-11-07 11:50:35 +0000
+++ b/sql/sql_time.h	2011-11-18 09:52:00 +0000
@@ -36,6 +36,11 @@ ulong convert_month_to_period(ulong mont
 void mix_date_and_time(MYSQL_TIME *ldate, const MYSQL_TIME *ltime);
 void get_date_from_daynr(long daynr,uint *year, uint *month, uint *day);
 my_time_t TIME_to_timestamp(THD *thd, const MYSQL_TIME *t, my_bool *not_exist);
+bool datetime_with_no_zero_in_date_to_timeval(THD *thd, const MYSQL_TIME *t,
+                                              struct timeval *tm,
+                                              int *warnings);
+bool datetime_to_timeval(THD *thd, const MYSQL_TIME *t,
+                         struct timeval *tm, int *warnings);
 bool str_to_datetime_with_warn(String *str,  MYSQL_TIME *l_time, uint flags);
 bool my_decimal_to_datetime_with_warn(const my_decimal *decimal,
                                       MYSQL_TIME *ltime, uint flags);

=== modified file 'unittest/gunit/field-t.cc'
--- a/unittest/gunit/field-t.cc	2011-11-01 11:52:24 +0000
+++ b/unittest/gunit/field-t.cc	2011-11-18 11:49:13 +0000
@@ -258,7 +258,8 @@ TEST_F(FieldTest, FieldTimef)
   // it requires a mock table
   
   struct timeval tv;
-  EXPECT_EQ(0, f->get_timestamp(&tv));
+  int warnings= 0;
+  EXPECT_EQ(0, f->get_timestamp(&tv, &warnings));
   // EXPECT_EQ(40992, tv.tv_sec);  // This is 11:23:12.  Why?  Time zone?
   EXPECT_EQ(123400, tv.tv_usec);
 

No bundle (reason: useless for push emails).
Thread
bzr push into mysql-trunk branch (alexander.barkov:3599 to 3600) Alexander Barkov21 Nov