Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
mariadb
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
mariadb
Commits
cb7e272e
Commit
cb7e272e
authored
Nov 19, 2004
by
dlenev@mysql.com
Browse files
Options
Browse Files
Download
Plain Diff
Manual merge of fix for bug #6266 "Invalid DATETIME value is not handled
properly" with main tree.
parents
03c28bf1
b02f5aa6
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
209 additions
and
34 deletions
+209
-34
include/my_time.h
include/my_time.h
+3
-2
include/mysql_time.h
include/mysql_time.h
+12
-0
libmysql/libmysql.c
libmysql/libmysql.c
+7
-6
mysql-test/r/type_datetime.result
mysql-test/r/type_datetime.result
+9
-2
mysql-test/t/type_datetime.test
mysql-test/t/type_datetime.test
+5
-2
sql-common/my_time.c
sql-common/my_time.c
+4
-3
sql/field.cc
sql/field.cc
+4
-0
sql/item.cc
sql/item.cc
+26
-0
sql/sql_prepare.cc
sql/sql_prepare.cc
+4
-19
tests/client_test.c
tests/client_test.c
+135
-0
No files found.
include/my_time.h
View file @
cb7e272e
...
...
@@ -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
...
...
include/mysql_time.h
View file @
cb7e272e
...
...
@@ -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
;
...
...
libmysql/libmysql.c
View file @
cb7e272e
...
...
@@ -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
);
}
...
...
mysql-test/r/type_datetime.result
View file @
cb7e272e
...
...
@@ -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:
...
...
mysql-test/t/type_datetime.test
View file @
cb7e272e
...
...
@@ -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"
);
...
...
sql-common/my_time.c
View file @
cb7e272e
...
...
@@ -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
;
}
...
...
sql/field.cc
View file @
cb7e272e
...
...
@@ -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
));
...
...
sql/item.cc
View file @
cb7e272e
...
...
@@ -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
;
...
...
sql/sql_prepare.cc
View file @
cb7e272e
...
...
@@ -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
;
...
...
tests/client_test.c
View file @
cb7e272e
...
...
@@ -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
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment