mirror of
https://github.com/MariaDB/server.git
synced 2025-01-18 04:53:01 +01:00
Merge bk-internal.mysql.com:/home/bk/mysql-4.1
into mysql.com:/home/dlenev/src/mysql-4.1-bg6266
This commit is contained in:
commit
4e52cc2ded
10 changed files with 209 additions and 34 deletions
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -3257,11 +3257,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)
|
||||
|
@ -3286,12 +3287,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)
|
||||
|
@ -3308,12 +3309,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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -343,7 +343,8 @@ str_to_datetime(const char *str, uint length, MYSQL_TIME *l_time,
|
|||
(l_time->month || l_time->day))
|
||||
l_time->year+= (l_time->year < YY_PART_YEAR ? 2000 : 1900);
|
||||
|
||||
if (number_of_fields < 3 || l_time->month > 12 ||
|
||||
if (number_of_fields < 3 ||
|
||||
l_time->year > 9999 || l_time->month > 12 ||
|
||||
l_time->day > 31 || l_time->hour > 23 ||
|
||||
l_time->minute > 59 || l_time->second > 59 ||
|
||||
(!(flags & TIME_FUZZY_DATE) && (l_time->month == 0 || l_time->day == 0)))
|
||||
|
@ -733,10 +734,10 @@ my_system_gmt_sec(const MYSQL_TIME *t, long *my_timezone, bool *in_dst_time_gap)
|
|||
|
||||
/* Set MYSQL_TIME structure to 0000-00-00 00:00:00.000000 */
|
||||
|
||||
void set_zero_time(MYSQL_TIME *tm)
|
||||
void set_zero_time(MYSQL_TIME *tm, enum enum_mysql_timestamp_type time_type)
|
||||
{
|
||||
bzero((void*) tm, sizeof(*tm));
|
||||
tm->time_type= MYSQL_TIMESTAMP_NONE;
|
||||
tm->time_type= time_type;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -4086,6 +4086,10 @@ int Field_datetime::store(longlong nr)
|
|||
void Field_datetime::store_time(TIME *ltime,timestamp_type type)
|
||||
{
|
||||
longlong tmp;
|
||||
/*
|
||||
We don't perform range checking here since values stored in TIME
|
||||
structure always fit into DATETIME range.
|
||||
*/
|
||||
if (type == MYSQL_TIMESTAMP_DATE || type == MYSQL_TIMESTAMP_DATETIME)
|
||||
tmp=((ltime->year*10000L+ltime->month*100+ltime->day)*LL(1000000)+
|
||||
(ltime->hour*10000L+ltime->minute*100+ltime->second));
|
||||
|
|
26
sql/item.cc
26
sql/item.cc
|
@ -837,6 +837,21 @@ void Item_param::set_double(double d)
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
Set parameter value from TIME value.
|
||||
|
||||
SYNOPSIS
|
||||
set_time()
|
||||
tm - datetime value to set (time_type is ignored)
|
||||
type - type of datetime value
|
||||
max_length_arg - max length of datetime value as string
|
||||
|
||||
NOTE
|
||||
If we value to be stored is not normalized, zero value will be stored
|
||||
instead and proper warning will be produced. This function relies on
|
||||
the fact that even wrong value sent over binary protocol fits into
|
||||
MAX_DATE_STRING_REP_LENGTH buffer.
|
||||
*/
|
||||
void Item_param::set_time(TIME *tm, timestamp_type type, uint32 max_length_arg)
|
||||
{
|
||||
DBUG_ENTER("Item_param::set_time");
|
||||
|
@ -844,6 +859,17 @@ void Item_param::set_time(TIME *tm, timestamp_type type, uint32 max_length_arg)
|
|||
value.time= *tm;
|
||||
value.time.time_type= type;
|
||||
|
||||
if (value.time.year > 9999 || value.time.month > 12 ||
|
||||
value.time.day > 31 ||
|
||||
type != MYSQL_TIMESTAMP_TIME && value.time.hour > 23 ||
|
||||
value.time.minute > 59 || value.time.second > 59)
|
||||
{
|
||||
char buff[MAX_DATE_STRING_REP_LENGTH];
|
||||
uint length= my_TIME_to_str(&value.time, buff);
|
||||
make_truncated_value_warning(current_thd, buff, length, type);
|
||||
set_zero_time(&value.time, MYSQL_TIMESTAMP_ERROR);
|
||||
}
|
||||
|
||||
state= TIME_VALUE;
|
||||
maybe_null= 0;
|
||||
max_length= max_length_arg;
|
||||
|
|
|
@ -349,12 +349,6 @@ static void set_param_time(Item_param *param, uchar **pos, ulong len)
|
|||
|
||||
tm.neg= (bool) to[0];
|
||||
day= (uint) sint4korr(to+1);
|
||||
/*
|
||||
Note, that though ranges of hour, minute and second are not checked
|
||||
here we rely on them being < 256: otherwise
|
||||
we'll get buffer overflow in make_{date,time} functions,
|
||||
which are called when time value is converted to string.
|
||||
*/
|
||||
tm.hour= (uint) to[5] + day * 24;
|
||||
tm.minute= (uint) to[6];
|
||||
tm.second= (uint) to[7];
|
||||
|
@ -369,7 +363,7 @@ static void set_param_time(Item_param *param, uchar **pos, ulong len)
|
|||
tm.day= tm.year= tm.month= 0;
|
||||
}
|
||||
else
|
||||
set_zero_time(&tm);
|
||||
set_zero_time(&tm, MYSQL_TIMESTAMP_TIME);
|
||||
param->set_time(&tm, MYSQL_TIMESTAMP_TIME,
|
||||
MAX_TIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
|
||||
*pos+= length;
|
||||
|
@ -388,11 +382,6 @@ static void set_param_datetime(Item_param *param, uchar **pos, ulong len)
|
|||
tm.year= (uint) sint2korr(to);
|
||||
tm.month= (uint) to[2];
|
||||
tm.day= (uint) to[3];
|
||||
/*
|
||||
Note, that though ranges of hour, minute and second are not checked
|
||||
here we rely on them being < 256: otherwise
|
||||
we'll get buffer overflow in make_{date,time} functions.
|
||||
*/
|
||||
if (length > 4)
|
||||
{
|
||||
tm.hour= (uint) to[4];
|
||||
|
@ -405,7 +394,7 @@ static void set_param_datetime(Item_param *param, uchar **pos, ulong len)
|
|||
tm.second_part= (length > 7) ? (ulong) sint4korr(to+7) : 0;
|
||||
}
|
||||
else
|
||||
set_zero_time(&tm);
|
||||
set_zero_time(&tm, MYSQL_TIMESTAMP_DATETIME);
|
||||
param->set_time(&tm, MYSQL_TIMESTAMP_DATETIME,
|
||||
MAX_DATETIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
|
||||
*pos+= length;
|
||||
|
@ -419,11 +408,7 @@ static void set_param_date(Item_param *param, uchar **pos, ulong len)
|
|||
if (length >= 4)
|
||||
{
|
||||
uchar *to= *pos;
|
||||
/*
|
||||
Note, that though ranges of hour, minute and second are not checked
|
||||
here we rely on them being < 256: otherwise
|
||||
we'll get buffer overflow in make_{date,time} functions.
|
||||
*/
|
||||
|
||||
tm.year= (uint) sint2korr(to);
|
||||
tm.month= (uint) to[2];
|
||||
tm.day= (uint) to[3];
|
||||
|
@ -433,7 +418,7 @@ static void set_param_date(Item_param *param, uchar **pos, ulong len)
|
|||
tm.neg= 0;
|
||||
}
|
||||
else
|
||||
set_zero_time(&tm);
|
||||
set_zero_time(&tm, MYSQL_TIMESTAMP_DATE);
|
||||
param->set_time(&tm, MYSQL_TIMESTAMP_DATE,
|
||||
MAX_DATE_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
|
||||
*pos+= length;
|
||||
|
|
|
@ -11121,6 +11121,140 @@ static void test_bug6096()
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
Test of basic checks that are performed in server for components
|
||||
of MYSQL_TIME parameters.
|
||||
*/
|
||||
|
||||
static void test_datetime_ranges()
|
||||
{
|
||||
const char *stmt_text;
|
||||
int rc, i;
|
||||
MYSQL_STMT *stmt;
|
||||
MYSQL_BIND bind[6];
|
||||
MYSQL_TIME tm[6];
|
||||
|
||||
myheader("test_datetime_ranges");
|
||||
|
||||
stmt_text= "drop table if exists t1";
|
||||
rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
|
||||
myquery(rc);
|
||||
|
||||
stmt_text= "create table t1 (year datetime, month datetime, day datetime, "
|
||||
"hour datetime, min datetime, sec datetime)";
|
||||
rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
|
||||
myquery(rc);
|
||||
|
||||
stmt= mysql_simple_prepare(mysql,
|
||||
"INSERT INTO t1 VALUES (?, ?, ?, ?, ?, ?)");
|
||||
check_stmt(stmt);
|
||||
verify_param_count(stmt, 6);
|
||||
|
||||
bzero(bind, sizeof(bind));
|
||||
for (i= 0; i < 6; i++)
|
||||
{
|
||||
bind[i].buffer_type= MYSQL_TYPE_DATETIME;
|
||||
bind[i].buffer= &tm[i];
|
||||
}
|
||||
rc= mysql_stmt_bind_param(stmt, bind);
|
||||
check_execute(stmt, rc);
|
||||
|
||||
tm[0].year= 2004; tm[0].month= 11; tm[0].day= 10;
|
||||
tm[0].hour= 12; tm[0].minute= 30; tm[0].second= 30;
|
||||
tm[0].second_part= 0; tm[0].neg= 0;
|
||||
|
||||
tm[5]= tm[4]= tm[3]= tm[2]= tm[1]= tm[0];
|
||||
tm[0].year= 10000; tm[1].month= 13; tm[2].day= 32;
|
||||
tm[3].hour= 24; tm[4].minute= 60; tm[5].second= 60;
|
||||
|
||||
rc= mysql_stmt_execute(stmt);
|
||||
check_execute(stmt, rc);
|
||||
DIE_UNLESS(mysql_warning_count(mysql) != 6);
|
||||
|
||||
verify_col_data("t1", "year", "0000-00-00 00:00:00");
|
||||
verify_col_data("t1", "month", "0000-00-00 00:00:00");
|
||||
verify_col_data("t1", "day", "0000-00-00 00:00:00");
|
||||
verify_col_data("t1", "hour", "0000-00-00 00:00:00");
|
||||
verify_col_data("t1", "min", "0000-00-00 00:00:00");
|
||||
verify_col_data("t1", "sec", "0000-00-00 00:00:00");
|
||||
|
||||
mysql_stmt_close(stmt);
|
||||
|
||||
stmt_text= "delete from t1";
|
||||
rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
|
||||
myquery(rc);
|
||||
|
||||
stmt= mysql_simple_prepare(mysql, "INSERT INTO t1 (year, month, day) "
|
||||
"VALUES (?, ?, ?)");
|
||||
check_stmt(stmt);
|
||||
verify_param_count(stmt, 3);
|
||||
|
||||
/*
|
||||
We reuse contents of bind and tm arrays left from previous part of test.
|
||||
*/
|
||||
for (i= 0; i < 3; i++)
|
||||
bind[i].buffer_type= MYSQL_TYPE_DATE;
|
||||
|
||||
rc= mysql_stmt_bind_param(stmt, bind);
|
||||
check_execute(stmt, rc);
|
||||
|
||||
rc= mysql_stmt_execute(stmt);
|
||||
check_execute(stmt, rc);
|
||||
DIE_UNLESS(mysql_warning_count(mysql) != 3);
|
||||
|
||||
verify_col_data("t1", "year", "0000-00-00 00:00:00");
|
||||
verify_col_data("t1", "month", "0000-00-00 00:00:00");
|
||||
verify_col_data("t1", "day", "0000-00-00 00:00:00");
|
||||
|
||||
mysql_stmt_close(stmt);
|
||||
|
||||
stmt_text= "drop table t1";
|
||||
rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
|
||||
myquery(rc);
|
||||
|
||||
stmt_text= "create table t1 (day_ovfl time, day time, hour time, min time, sec time)";
|
||||
rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
|
||||
myquery(rc);
|
||||
|
||||
stmt= mysql_simple_prepare(mysql,
|
||||
"INSERT INTO t1 VALUES (?, ?, ?, ?, ?)");
|
||||
check_stmt(stmt);
|
||||
verify_param_count(stmt, 5);
|
||||
|
||||
/*
|
||||
Again we reuse what we can from previous part of test.
|
||||
*/
|
||||
for (i= 0; i < 5; i++)
|
||||
bind[i].buffer_type= MYSQL_TYPE_TIME;
|
||||
|
||||
rc= mysql_stmt_bind_param(stmt, bind);
|
||||
check_execute(stmt, rc);
|
||||
|
||||
tm[0].year= 0; tm[0].month= 0; tm[0].day= 10;
|
||||
tm[0].hour= 12; tm[0].minute= 30; tm[0].second= 30;
|
||||
tm[0].second_part= 0; tm[0].neg= 0;
|
||||
|
||||
tm[4]= tm[3]= tm[2]= tm[1]= tm[0];
|
||||
tm[0].day= 35; tm[1].day= 34; tm[2].hour= 30; tm[3].minute= 60; tm[4].second= 60;
|
||||
|
||||
rc= mysql_stmt_execute(stmt);
|
||||
check_execute(stmt, rc);
|
||||
DIE_UNLESS(mysql_warning_count(mysql) != 2);
|
||||
|
||||
verify_col_data("t1", "day_ovfl", "838:59:59");
|
||||
verify_col_data("t1", "day", "828:30:30");
|
||||
verify_col_data("t1", "hour", "270:30:30");
|
||||
verify_col_data("t1", "min", "00:00:00");
|
||||
verify_col_data("t1", "sec", "00:00:00");
|
||||
|
||||
mysql_stmt_close(stmt);
|
||||
|
||||
stmt_text= "drop table t1";
|
||||
rc= mysql_real_query(mysql, stmt_text, strlen(stmt_text));
|
||||
myquery(rc);
|
||||
}
|
||||
|
||||
|
||||
static void test_bug4172()
|
||||
{
|
||||
MYSQL_STMT *stmt;
|
||||
|
@ -11455,6 +11589,7 @@ static struct my_tests_st my_tests[]= {
|
|||
{ "test_bug6046", test_bug6046 },
|
||||
{ "test_bug6081", test_bug6081 },
|
||||
{ "test_bug6096", test_bug6096 },
|
||||
{ "test_datetime_ranges", test_datetime_ranges },
|
||||
{ "test_bug4172", test_bug4172 },
|
||||
{ "test_conversion", test_conversion },
|
||||
{ 0, 0 }
|
||||
|
|
Loading…
Reference in a new issue