Commit 5d9f7edd authored by unknown's avatar unknown
Browse files

Fix for bug #6266 "Invalid DATETIME value is not handled properly".

In server we assume that datetime values stored in MYSQL_TIME struct
are normalized (and year is not greater than 9999), so we should 
perform range checks in all places then we convert something to
MYSQL_TIME. 


include/my_time.h:
  Added one more argument to set_zero_time() function to make it more 
  convinient.
  Added comment clarifying why MAX_DATE_STRING_REP_LENGTH value is 30.
include/mysql_time.h:
  Documented MySQL's internal assumptions for members of MYSQL_TIME
  structure.
libmysql/libmysql.c:
  It does not make sense to set MYSQL_TIME::time_type twice in case of 
  errors.
mysql-test/r/type_datetime.result:
  Added test for bug #6266 "Invalid DATETIME value not handled properly".
mysql-test/t/type_datetime.test:
  Added test for bug #6266 "Invalid DATETIME value not handled properly".
sql-common/my_time.c:
  str_to_datetime(): Added missing check for too big year values.
  set_zero_time(): added time_type argument, since MYSQL_TIMESTAMP_NONE
    is not the value that we want in most cases.
sql/field.cc:
  Field_datetime::store_time():
    clarified why we don't perform any range checks here.
sql/item.cc:
  Item_param::set_time():
   Added comment describing this method and range checking for TIME
   values.
sql/sql_prepare.cc:
  Removed comments about range checking for TIME values in prepared 
  statements, which are no longer true.
  set_zero_time() has one more argument now.
tests/client_test.c:
  Added test for bug #6266 "Invalid DATETIME value not handled properly"
parent 7fd0cc2d
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -58,14 +58,15 @@ void init_time(void);
my_time_t 
my_system_gmt_sec(const MYSQL_TIME *t, long *my_timezone, bool *in_dst_time_gap);

void set_zero_time(MYSQL_TIME *tm);
void set_zero_time(MYSQL_TIME *tm, enum enum_mysql_timestamp_type time_type);

/*
  Required buffer length for my_time_to_str, my_date_to_str,
  my_datetime_to_str and TIME_to_string functions. Note, that the
  caller is still responsible to check that given TIME structure
  has values in valid ranges, otherwise size of the buffer could
  be not enough.
  be not enough. We also rely on the fact that even wrong values
  sent using binary protocol fit in this buffer.
*/
#define MAX_DATE_STRING_REP_LENGTH 30

+12 −0
Original line number Diff line number Diff line
@@ -33,6 +33,18 @@ enum enum_mysql_timestamp_type
};


/*
  Structure which is used to represent datetime values inside MySQL.

  We assume that values in this structure are normalized, i.e. year <= 9999,
  month <= 12, day <= 31, hour <= 23, hour <= 59, hour <= 59. Many functions
  in server such as my_system_gmt_sec() or make_time() family of functions
  rely on this (actually now usage of make_*() family relies on a bit weaker
  restriction). Also functions that produce MYSQL_TIME as result ensure this.
  There is one exception to this rule though if this structure holds time
  value (time_type == MYSQL_TIMESTAMP_TIME) days and hour member can hold
  bigger values.
*/
typedef struct st_mysql_time
{
  unsigned int  year, month, day, hour, minute, second;
+7 −6
Original line number Diff line number Diff line
@@ -3256,11 +3256,12 @@ static void read_binary_time(MYSQL_TIME *tm, uchar **pos)
      tm->hour+= tm->day*24;
      tm->day= 0;
    }
    tm->time_type= MYSQL_TIMESTAMP_TIME;

    *pos+= length;
  }
  else
    set_zero_time(tm);
  tm->time_type= MYSQL_TIMESTAMP_TIME;
    set_zero_time(tm, MYSQL_TIMESTAMP_TIME);
}

static void read_binary_datetime(MYSQL_TIME *tm, uchar **pos)
@@ -3285,12 +3286,12 @@ static void read_binary_datetime(MYSQL_TIME *tm, uchar **pos)
    else
      tm->hour= tm->minute= tm->second= 0;
    tm->second_part= (length > 7) ? (ulong) sint4korr(to+7) : 0;
    tm->time_type= MYSQL_TIMESTAMP_DATETIME;

    *pos+= length;
  }
  else
    set_zero_time(tm);
  tm->time_type= MYSQL_TIMESTAMP_DATETIME;
    set_zero_time(tm, MYSQL_TIMESTAMP_DATETIME);
}

static void read_binary_date(MYSQL_TIME *tm, uchar **pos)
@@ -3307,12 +3308,12 @@ static void read_binary_date(MYSQL_TIME *tm, uchar **pos)
    tm->hour= tm->minute= tm->second= 0;
    tm->second_part= 0;
    tm->neg= 0;
    tm->time_type= MYSQL_TIMESTAMP_DATE;

    *pos+= length;
  }
  else
    set_zero_time(tm);
  tm->time_type= MYSQL_TIMESTAMP_DATE;
    set_zero_time(tm, MYSQL_TIMESTAMP_DATE);
}


+9 −2
Original line number Diff line number Diff line
@@ -97,13 +97,15 @@ select * from t1 where a is null or b is null;
a	b
drop table t1;
create table t1 (t datetime);
insert into t1 values (20030102030460),(20030102036301),(20030102240401),(20030132030401),(20031302030460);
insert into t1 values (20030102030460),(20030102036301),(20030102240401),
(20030132030401),(20031302030401),(100001202030401);
Warnings:
Warning	1265	Data truncated for column 't' at row 1
Warning	1265	Data truncated for column 't' at row 2
Warning	1265	Data truncated for column 't' at row 3
Warning	1265	Data truncated for column 't' at row 4
Warning	1265	Data truncated for column 't' at row 5
Warning	1265	Data truncated for column 't' at row 6
select * from t1;
t
0000-00-00 00:00:00
@@ -111,14 +113,18 @@ t
0000-00-00 00:00:00
0000-00-00 00:00:00
0000-00-00 00:00:00
0000-00-00 00:00:00
delete from t1;
insert into t1 values ("20030102030460"),("20030102036301"),("20030102240401"),("20030132030401"),("20031302030460");
insert into t1 values
("2003-01-02 03:04:60"),("2003-01-02 03:63:01"),("2003-01-02 24:04:01"),
("2003-01-32 03:04:01"),("2003-13-02 03:04:01"), ("10000-12-02 03:04:00");
Warnings:
Warning	1264	Data truncated; out of range for column 't' at row 1
Warning	1264	Data truncated; out of range for column 't' at row 2
Warning	1264	Data truncated; out of range for column 't' at row 3
Warning	1264	Data truncated; out of range for column 't' at row 4
Warning	1264	Data truncated; out of range for column 't' at row 5
Warning	1264	Data truncated; out of range for column 't' at row 6
select * from t1;
t
0000-00-00 00:00:00
@@ -126,6 +132,7 @@ t
0000-00-00 00:00:00
0000-00-00 00:00:00
0000-00-00 00:00:00
0000-00-00 00:00:00
delete from t1;
insert into t1 values ("0000-00-00 00:00:00 some trailer"),("2003-01-01 00:00:00 some trailer");
Warnings:
+5 −2
Original line number Diff line number Diff line
@@ -77,10 +77,13 @@ drop table t1;
# warnings (for both strings and numbers)
#
create table t1 (t datetime);
insert into t1 values (20030102030460),(20030102036301),(20030102240401),(20030132030401),(20031302030460);
insert into t1 values (20030102030460),(20030102036301),(20030102240401),
                      (20030132030401),(20031302030401),(100001202030401);
select * from t1;
delete from t1;
insert into t1 values ("20030102030460"),("20030102036301"),("20030102240401"),("20030132030401"),("20031302030460");
insert into t1 values
  ("2003-01-02 03:04:60"),("2003-01-02 03:63:01"),("2003-01-02 24:04:01"),
  ("2003-01-32 03:04:01"),("2003-13-02 03:04:01"), ("10000-12-02 03:04:00");
select * from t1;
delete from t1;
insert into t1 values ("0000-00-00 00:00:00 some trailer"),("2003-01-01 00:00:00 some trailer");
Loading