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
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexedi
MariaDB
Commits
4087683e
Commit
4087683e
authored
Feb 12, 2018
by
Alexander Barkov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
MDEV-15287 Bad result for LEAST/GREATEST(datetime_alike_string, time)
parent
da99e086
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
289 additions
and
0 deletions
+289
-0
mysql-test/r/type_time.result
mysql-test/r/type_time.result
+75
-0
mysql-test/t/type_time.test
mysql-test/t/type_time.test
+52
-0
sql/item_func.cc
sql/item_func.cc
+23
-0
sql/item_func.h
sql/item_func.h
+1
-0
sql/sql_type.cc
sql/sql_type.cc
+16
-0
sql/sql_type.h
sql/sql_type.h
+122
-0
No files found.
mysql-test/r/type_time.result
View file @
4087683e
...
...
@@ -1412,3 +1412,78 @@ d t0 t1
DROP TABLE t1;
DROP TABLE t0;
SET sql_mode=DEFAULT;
#
# MDEV-15287 Bad result for LEAST/GREATEST(datetime_alike_string, time)
#
SELECT
GREATEST('2010-01-01 10:10:10',TIME('-20:20:20')) AS gt_minus20_implicit,
GREATEST(CAST('2010-01-01 10:10:10' AS TIME(6)),TIME('-20:20:20')) AS gt_minis20_explicit,
GREATEST('2010-01-01 10:10:10',TIME('20:20:20')) AS gt_plus20_implicit,
GREATEST(CAST('2010-01-01 10:10:10' AS TIME(6)),TIME('20:20:20')) AS gt_plus20_explicit;
gt_minus20_implicit 10:10:10.000000
gt_minis20_explicit 10:10:10.000000
gt_plus20_implicit 20:20:20.000000
gt_plus20_explicit 20:20:20.000000
SELECT
HOUR(GREATEST('2010-01-01 10:10:10',TIME('-20:20:20'))) AS gt_minus20_implicit,
HOUR(GREATEST(CAST('2010-01-01 10:10:10' AS TIME(6)),TIME('-20:20:20'))) AS gt_minis20_explicit,
HOUR(GREATEST('2010-01-01 10:10:10',TIME('20:20:20'))) AS gt_plus20_implicit,
HOUR(GREATEST(CAST('2010-01-01 10:10:10' AS TIME(6)),TIME('20:20:20'))) AS gt_plus20_explicit;
gt_minus20_implicit 10
gt_minis20_explicit 10
gt_plus20_implicit 20
gt_plus20_explicit 20
SELECT
LEAST('2010-01-01 10:10:10',TIME('-20:20:20')) AS lt_minus20_implicit,
LEAST(CAST('2010-01-01 10:10:10' AS TIME(6)),TIME('-20:20:20')) AS lt_minus20_explicit,
LEAST('2010-01-01 10:10:10',TIME('20:20:20')) AS lt_plus20_implicit,
LEAST(CAST('2010-01-01 10:10:10' AS TIME(6)),TIME('20:20:20')) AS lt_plus20_explicit;
lt_minus20_implicit -20:20:20.000000
lt_minus20_explicit -20:20:20.000000
lt_plus20_implicit 10:10:10.000000
lt_plus20_explicit 10:10:10.000000
SELECT
HOUR(LEAST('2010-01-01 10:10:10',TIME('-20:20:20'))) AS lt_minus20_implicit,
HOUR(LEAST(CAST('2010-01-01 10:10:10' AS TIME(6)),TIME('-20:20:20'))) AS lt_minus20_explicit,
HOUR(LEAST('2010-01-01 10:10:10',TIME('20:20:20'))) AS lt_plus20_implicit,
HOUR(LEAST(CAST('2010-01-01 10:10:10' AS TIME(6)),TIME('20:20:20'))) AS lt_plus20_explicit;
lt_minus20_implicit 20
lt_minus20_explicit 20
lt_plus20_implicit 10
lt_plus20_explicit 10
SELECT
GREATEST('2010-01-01 10:10:10',TIME('-200:20:20')) AS gt_minus200_implicit,
GREATEST(CAST('2010-01-01 10:10:10' AS TIME(6)),TIME('-200:20:20')) AS gt_minus200_explictit,
GREATEST('2010-01-01 10:10:10',TIME('200:20:20')) AS gt_plus200_implicit,
GREATEST(CAST('2010-01-01 10:10:10' AS TIME(6)),TIME('200:20:20')) AS gt_plus200_explicit;
gt_minus200_implicit 10:10:10.000000
gt_minus200_explictit 10:10:10.000000
gt_plus200_implicit 200:20:20.000000
gt_plus200_explicit 200:20:20.000000
SELECT
HOUR(GREATEST('2010-01-01 10:10:10',TIME('-200:20:20'))) AS gt_minus200_implicit,
HOUR(GREATEST(CAST('2010-01-01 10:10:10' AS TIME(6)),TIME('-200:20:20'))) AS gt_minus200_explictit,
HOUR(GREATEST('2010-01-01 10:10:10',TIME('200:20:20'))) AS gt_plus200_implicit,
HOUR(GREATEST(CAST('2010-01-01 10:10:10' AS TIME(6)),TIME('200:20:20'))) AS gt_plus200_explicit;
gt_minus200_implicit 10
gt_minus200_explictit 10
gt_plus200_implicit 200
gt_plus200_explicit 200
SELECT
LEAST('2010-01-01 10:10:10',TIME('-200:20:20')) AS lt_minus200_implicit,
LEAST(CAST('2010-01-01 10:10:10' AS TIME(6)),TIME('-200:20:20')) AS lt_minus200_explictit,
LEAST('2010-01-01 10:10:10',TIME('200:20:20')) AS lt_plus200_implicit,
LEAST(CAST('2010-01-01 10:10:10' AS TIME(6)),TIME('200:20:20')) AS lt_plus200_explicit;
lt_minus200_implicit -200:20:20.000000
lt_minus200_explictit -200:20:20.000000
lt_plus200_implicit 10:10:10.000000
lt_plus200_explicit 10:10:10.000000
SELECT
HOUR(LEAST('2010-01-01 10:10:10',TIME('-200:20:20'))) AS lt_minus200_implicit,
HOUR(LEAST(CAST('2010-01-01 10:10:10' AS TIME(6)),TIME('-200:20:20'))) AS lt_minus200_explictit,
HOUR(LEAST('2010-01-01 10:10:10',TIME('200:20:20'))) AS lt_plus200_implicit,
HOUR(LEAST(CAST('2010-01-01 10:10:10' AS TIME(6)),TIME('200:20:20'))) AS lt_plus200_explicit;
lt_minus200_implicit 200
lt_minus200_explictit 200
lt_plus200_implicit 10
lt_plus200_explicit 10
mysql-test/t/type_time.test
View file @
4087683e
...
...
@@ -814,3 +814,55 @@ DROP TABLE t1;
DROP
TABLE
t0
;
SET
sql_mode
=
DEFAULT
;
--
echo
#
--
echo
# MDEV-15287 Bad result for LEAST/GREATEST(datetime_alike_string, time)
--
echo
#
--
vertical_results
SELECT
GREATEST
(
'2010-01-01 10:10:10'
,
TIME
(
'-20:20:20'
))
AS
gt_minus20_implicit
,
GREATEST
(
CAST
(
'2010-01-01 10:10:10'
AS
TIME
(
6
)),
TIME
(
'-20:20:20'
))
AS
gt_minis20_explicit
,
GREATEST
(
'2010-01-01 10:10:10'
,
TIME
(
'20:20:20'
))
AS
gt_plus20_implicit
,
GREATEST
(
CAST
(
'2010-01-01 10:10:10'
AS
TIME
(
6
)),
TIME
(
'20:20:20'
))
AS
gt_plus20_explicit
;
SELECT
HOUR
(
GREATEST
(
'2010-01-01 10:10:10'
,
TIME
(
'-20:20:20'
)))
AS
gt_minus20_implicit
,
HOUR
(
GREATEST
(
CAST
(
'2010-01-01 10:10:10'
AS
TIME
(
6
)),
TIME
(
'-20:20:20'
)))
AS
gt_minis20_explicit
,
HOUR
(
GREATEST
(
'2010-01-01 10:10:10'
,
TIME
(
'20:20:20'
)))
AS
gt_plus20_implicit
,
HOUR
(
GREATEST
(
CAST
(
'2010-01-01 10:10:10'
AS
TIME
(
6
)),
TIME
(
'20:20:20'
)))
AS
gt_plus20_explicit
;
SELECT
LEAST
(
'2010-01-01 10:10:10'
,
TIME
(
'-20:20:20'
))
AS
lt_minus20_implicit
,
LEAST
(
CAST
(
'2010-01-01 10:10:10'
AS
TIME
(
6
)),
TIME
(
'-20:20:20'
))
AS
lt_minus20_explicit
,
LEAST
(
'2010-01-01 10:10:10'
,
TIME
(
'20:20:20'
))
AS
lt_plus20_implicit
,
LEAST
(
CAST
(
'2010-01-01 10:10:10'
AS
TIME
(
6
)),
TIME
(
'20:20:20'
))
AS
lt_plus20_explicit
;
SELECT
HOUR
(
LEAST
(
'2010-01-01 10:10:10'
,
TIME
(
'-20:20:20'
)))
AS
lt_minus20_implicit
,
HOUR
(
LEAST
(
CAST
(
'2010-01-01 10:10:10'
AS
TIME
(
6
)),
TIME
(
'-20:20:20'
)))
AS
lt_minus20_explicit
,
HOUR
(
LEAST
(
'2010-01-01 10:10:10'
,
TIME
(
'20:20:20'
)))
AS
lt_plus20_implicit
,
HOUR
(
LEAST
(
CAST
(
'2010-01-01 10:10:10'
AS
TIME
(
6
)),
TIME
(
'20:20:20'
)))
AS
lt_plus20_explicit
;
SELECT
GREATEST
(
'2010-01-01 10:10:10'
,
TIME
(
'-200:20:20'
))
AS
gt_minus200_implicit
,
GREATEST
(
CAST
(
'2010-01-01 10:10:10'
AS
TIME
(
6
)),
TIME
(
'-200:20:20'
))
AS
gt_minus200_explictit
,
GREATEST
(
'2010-01-01 10:10:10'
,
TIME
(
'200:20:20'
))
AS
gt_plus200_implicit
,
GREATEST
(
CAST
(
'2010-01-01 10:10:10'
AS
TIME
(
6
)),
TIME
(
'200:20:20'
))
AS
gt_plus200_explicit
;
SELECT
HOUR
(
GREATEST
(
'2010-01-01 10:10:10'
,
TIME
(
'-200:20:20'
)))
AS
gt_minus200_implicit
,
HOUR
(
GREATEST
(
CAST
(
'2010-01-01 10:10:10'
AS
TIME
(
6
)),
TIME
(
'-200:20:20'
)))
AS
gt_minus200_explictit
,
HOUR
(
GREATEST
(
'2010-01-01 10:10:10'
,
TIME
(
'200:20:20'
)))
AS
gt_plus200_implicit
,
HOUR
(
GREATEST
(
CAST
(
'2010-01-01 10:10:10'
AS
TIME
(
6
)),
TIME
(
'200:20:20'
)))
AS
gt_plus200_explicit
;
SELECT
LEAST
(
'2010-01-01 10:10:10'
,
TIME
(
'-200:20:20'
))
AS
lt_minus200_implicit
,
LEAST
(
CAST
(
'2010-01-01 10:10:10'
AS
TIME
(
6
)),
TIME
(
'-200:20:20'
))
AS
lt_minus200_explictit
,
LEAST
(
'2010-01-01 10:10:10'
,
TIME
(
'200:20:20'
))
AS
lt_plus200_implicit
,
LEAST
(
CAST
(
'2010-01-01 10:10:10'
AS
TIME
(
6
)),
TIME
(
'200:20:20'
))
AS
lt_plus200_explicit
;
SELECT
HOUR
(
LEAST
(
'2010-01-01 10:10:10'
,
TIME
(
'-200:20:20'
)))
AS
lt_minus200_implicit
,
HOUR
(
LEAST
(
CAST
(
'2010-01-01 10:10:10'
AS
TIME
(
6
)),
TIME
(
'-200:20:20'
)))
AS
lt_minus200_explictit
,
HOUR
(
LEAST
(
'2010-01-01 10:10:10'
,
TIME
(
'200:20:20'
)))
AS
lt_plus200_implicit
,
HOUR
(
LEAST
(
CAST
(
'2010-01-01 10:10:10'
AS
TIME
(
6
)),
TIME
(
'200:20:20'
)))
AS
lt_plus200_explicit
;
--
horizontal_results
sql/item_func.cc
View file @
4087683e
...
...
@@ -2739,6 +2739,29 @@ bool Item_func_min_max::get_date_native(MYSQL_TIME *ltime, ulonglong fuzzy_date)
}
bool
Item_func_min_max
::
get_time_native
(
MYSQL_TIME
*
ltime
)
{
DBUG_ASSERT
(
fixed
==
1
);
Time
value
(
args
[
0
]);
if
(
!
value
.
is_valid_time
())
return
(
null_value
=
true
);
for
(
uint
i
=
1
;
i
<
arg_count
;
i
++
)
{
Time
tmp
(
args
[
i
]);
if
(
!
tmp
.
is_valid_time
())
return
(
null_value
=
true
);
int
cmp
=
value
.
cmp
(
&
tmp
);
if
((
cmp_sign
<
0
?
cmp
:
-
cmp
)
<
0
)
value
=
tmp
;
}
value
.
copy_to_mysql_time
(
ltime
);
return
(
null_value
=
0
);
}
String
*
Item_func_min_max
::
val_str_native
(
String
*
str
)
{
String
*
UNINIT_VAR
(
res
);
...
...
sql/item_func.h
View file @
4087683e
...
...
@@ -1496,6 +1496,7 @@ class Item_func_min_max :public Item_hybrid_func
longlong
val_int_native
();
my_decimal
*
val_decimal_native
(
my_decimal
*
);
bool
get_date_native
(
MYSQL_TIME
*
res
,
ulonglong
fuzzydate
);
bool
get_time_native
(
MYSQL_TIME
*
res
);
double
val_real
()
{
...
...
sql/sql_type.cc
View file @
4087683e
...
...
@@ -121,6 +121,15 @@ bool Type_handler_data::init()
Type_handler_data
*
type_handler_data
=
NULL
;
void
Time
::
make_from_item
(
Item
*
item
)
{
if
(
item
->
get_time
(
this
))
time_type
=
MYSQL_TIMESTAMP_NONE
;
else
valid_MYSQL_TIME_to_valid_value
();
}
void
Type_std_attributes
::
set
(
const
Field
*
field
)
{
decimals
=
field
->
decimals
();
...
...
@@ -3902,6 +3911,13 @@ bool Type_handler_temporal_result::
return
func
->
get_date_native
(
ltime
,
fuzzydate
);
}
bool
Type_handler_time_common
::
Item_func_min_max_get_date
(
Item_func_min_max
*
func
,
MYSQL_TIME
*
ltime
,
ulonglong
fuzzydate
)
const
{
return
func
->
get_time_native
(
ltime
);
}
/***************************************************************************/
/**
...
...
sql/sql_type.h
View file @
4087683e
...
...
@@ -74,6 +74,126 @@ struct TABLE;
struct
SORT_FIELD_ATTR
;
/**
Class Time is designed to store valid TIME values.
1. Valid value:
a. MYSQL_TIMESTAMP_TIME - a valid TIME within the supported TIME range
b. MYSQL_TIMESTAMP_NONE - an undefined value
2. Invalid value (internally only):
a. MYSQL_TIMESTAMP_TIME outside of the supported TIME range
a. MYSQL_TIMESTAMP_{DATE|DATETIME|ERROR}
Temporarily Time is allowed to have an invalid value, but only internally,
during initialization time. All constructors and modification methods must
leave the Time value as described above (see "Valid values").
Time derives from MYSQL_TIME privately to make sure it is accessed
externally only in the valid state.
*/
class
Time
:
private
MYSQL_TIME
{
bool
is_valid_value_slow
()
const
{
return
time_type
==
MYSQL_TIMESTAMP_NONE
||
is_valid_time_slow
();
}
bool
is_valid_time_slow
()
const
{
return
time_type
==
MYSQL_TIMESTAMP_TIME
&&
year
==
0
&&
month
==
0
&&
day
==
0
&&
minute
<=
TIME_MAX_MINUTE
&&
second
<=
TIME_MAX_SECOND
&&
second_part
<=
TIME_MAX_SECOND_PART
;
}
/*
Convert a valid DATE or DATETIME to TIME.
Before this call, "this" must be a valid DATE or DATETIME value,
e.g. returned from Item::get_date().
After this call, "this" is a valid TIME value.
*/
void
valid_datetime_to_valid_time
()
{
DBUG_ASSERT
(
time_type
==
MYSQL_TIMESTAMP_DATE
||
time_type
==
MYSQL_TIMESTAMP_DATETIME
);
/*
Make sure that day and hour are valid, so the result hour value
after mixing days to hours does not go out of the valid TIME range.
*/
DBUG_ASSERT
(
day
<
32
);
DBUG_ASSERT
(
hour
<
24
);
if
(
year
==
0
&&
month
==
0
)
{
/*
The maximum hour value after mixing days will be 31*24+23=767,
which is within the supported TIME range.
Thus no adjust_time_range_or_invalidate() is needed here.
*/
hour
+=
day
*
24
;
}
year
=
month
=
day
=
0
;
time_type
=
MYSQL_TIMESTAMP_TIME
;
DBUG_ASSERT
(
is_valid_time_slow
());
}
/**
Convert valid DATE/DATETIME to valid TIME if needed.
This method is called after Item::get_date(),
which can return only valid TIME/DATE/DATETIME values.
Before this call, "this" is:
- either a valid TIME/DATE/DATETIME value
(within the supported range for the corresponding type),
- or MYSQL_TIMESTAMP_NONE
After this call, "this" is:
- either a valid TIME (within the supported TIME range),
- or MYSQL_TIMESTAMP_NONE
*/
void
valid_MYSQL_TIME_to_valid_value
()
{
switch
(
time_type
)
{
case
MYSQL_TIMESTAMP_DATE
:
case
MYSQL_TIMESTAMP_DATETIME
:
valid_datetime_to_valid_time
();
break
;
case
MYSQL_TIMESTAMP_NONE
:
break
;
case
MYSQL_TIMESTAMP_ERROR
:
set_zero_time
(
this
,
MYSQL_TIMESTAMP_TIME
);
break
;
case
MYSQL_TIMESTAMP_TIME
:
DBUG_ASSERT
(
is_valid_time_slow
());
break
;
}
}
void
make_from_item
(
class
Item
*
item
);
public:
Time
()
{
time_type
=
MYSQL_TIMESTAMP_NONE
;
}
Time
(
Item
*
item
)
{
make_from_item
(
item
);
}
bool
is_valid_time
()
const
{
DBUG_ASSERT
(
is_valid_value_slow
());
return
time_type
==
MYSQL_TIMESTAMP_TIME
;
}
void
copy_to_mysql_time
(
MYSQL_TIME
*
ltime
)
const
{
DBUG_ASSERT
(
is_valid_time_slow
());
*
ltime
=
*
this
;
}
int
cmp
(
const
Time
*
other
)
const
{
DBUG_ASSERT
(
is_valid_time_slow
());
DBUG_ASSERT
(
other
->
is_valid_time_slow
());
longlong
p0
=
pack_time
(
this
);
longlong
p1
=
pack_time
(
other
);
if
(
p0
<
p1
)
return
-
1
;
if
(
p0
>
p1
)
return
1
;
return
0
;
}
};
/*
Flags for collation aggregation modes, used in TDCollation::agg():
...
...
@@ -2086,6 +2206,8 @@ class Type_handler_time_common: public Type_handler_temporal_result
Type_handler_hybrid_field_type
*
,
Type_all_attributes
*
atrr
,
Item
**
items
,
uint
nitems
)
const
;
bool
Item_func_min_max_get_date
(
Item_func_min_max
*
,
MYSQL_TIME
*
,
ulonglong
fuzzydate
)
const
;
Item
*
make_const_item_for_comparison
(
THD
*
,
Item
*
src
,
const
Item
*
cmp
)
const
;
bool
set_comparator_func
(
Arg_comparator
*
cmp
)
const
;
cmp_item
*
make_cmp_item
(
THD
*
thd
,
CHARSET_INFO
*
cs
)
const
;
...
...
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