Skip to content

Commit

Permalink
MDEV-23311 CEILING() and FLOOR() convert temporal input to numbers, u…
Browse files Browse the repository at this point in the history
…nlike ROUND() and TRUNCATE()

Fixing functions CEILING and FLOOR to return
- TIME for TIME input
- DATETIME for DATETIME and TIMESTAMP input
  • Loading branch information
abarkov committed Jul 28, 2020
1 parent 69cf630 commit 5b3b53c
Show file tree
Hide file tree
Showing 14 changed files with 827 additions and 12 deletions.
7 changes: 7 additions & 0 deletions include/my_time.h
Original file line number Diff line number Diff line change
Expand Up @@ -233,9 +233,16 @@ static inline long my_time_fraction_remainder(long nr, uint decimals)
DBUG_ASSERT(decimals <= TIME_SECOND_PART_DIGITS);
return nr % (long) log_10_int[TIME_SECOND_PART_DIGITS - decimals];
}
static inline void my_datetime_trunc(MYSQL_TIME *ltime, uint decimals)
{
ltime->second_part-= my_time_fraction_remainder(ltime->second_part, decimals);
}
static inline void my_time_trunc(MYSQL_TIME *ltime, uint decimals)
{
ltime->second_part-= my_time_fraction_remainder(ltime->second_part, decimals);
if (!ltime->second_part && ltime->neg &&
!ltime->hour && !ltime->minute && !ltime->second)
ltime->neg= FALSE;
}
static inline void my_timeval_trunc(struct timeval *tv, uint decimals)
{
Expand Down
165 changes: 165 additions & 0 deletions mysql-test/main/type_datetime_hires.result
Original file line number Diff line number Diff line change
Expand Up @@ -900,5 +900,170 @@ f
NULL
DROP TABLE t1;
#
# MDEV-23311 CEILING() and FLOOR() convert temporal input to numbers, unlike ROUND() and TRUNCATE()
#
CREATE TABLE t1 AS SELECT
FLOOR(TIMESTAMP'2001-01-01 00:00:00.999999'),
CEILING(TIMESTAMP'2001-01-01 00:00:00.999999');
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`FLOOR(TIMESTAMP'2001-01-01 00:00:00.999999')` datetime DEFAULT NULL,
`CEILING(TIMESTAMP'2001-01-01 00:00:00.999999')` datetime DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
DROP TABLE t1;
CREATE TABLE t1 (a DATETIME(6));
INSERT INTO t1 VALUES ('9999-12-31 23:59:59.999999');
INSERT INTO t1 VALUES ('9999-12-31 23:59:59.99999');
INSERT INTO t1 VALUES ('9999-12-31 23:59:59.9999');
INSERT INTO t1 VALUES ('9999-12-31 23:59:59.999');
INSERT INTO t1 VALUES ('9999-12-31 23:59:59.99');
INSERT INTO t1 VALUES ('9999-12-31 23:59:59.9');
INSERT INTO t1 VALUES ('9999-12-31 23:59:59.1');
INSERT INTO t1 VALUES ('9999-12-31 23:59:59.0');
INSERT INTO t1 VALUES ('9999-12-30 23:59:59.999999');
INSERT INTO t1 VALUES ('9999-12-30 23:59:59.99999');
INSERT INTO t1 VALUES ('9999-12-30 23:59:59.9999');
INSERT INTO t1 VALUES ('9999-12-30 23:59:59.999');
INSERT INTO t1 VALUES ('9999-12-30 23:59:59.99');
INSERT INTO t1 VALUES ('9999-12-30 23:59:59.9');
INSERT INTO t1 VALUES ('9999-12-30 23:59:59.1');
INSERT INTO t1 VALUES ('9999-12-30 23:59:59.0');
INSERT INTO t1 VALUES ('0999-12-31 23:59:59.999999');
INSERT INTO t1 VALUES ('0999-12-31 23:59:59.99999');
INSERT INTO t1 VALUES ('0999-12-31 23:59:59.9999');
INSERT INTO t1 VALUES ('0999-12-31 23:59:59.999');
INSERT INTO t1 VALUES ('0999-12-31 23:59:59.99');
INSERT INTO t1 VALUES ('0999-12-31 23:59:59.9');
INSERT INTO t1 VALUES ('0999-12-31 23:59:59.1');
INSERT INTO t1 VALUES ('0999-12-31 23:59:59.0');
INSERT INTO t1 VALUES ('0001-12-31 23:59:59.999999');
INSERT INTO t1 VALUES ('0001-12-31 23:59:59.99999');
INSERT INTO t1 VALUES ('0001-12-31 23:59:59.9999');
INSERT INTO t1 VALUES ('0001-12-31 23:59:59.999');
INSERT INTO t1 VALUES ('0001-12-31 23:59:59.99');
INSERT INTO t1 VALUES ('0001-12-31 23:59:59.9');
INSERT INTO t1 VALUES ('0001-12-31 23:59:59.1');
INSERT INTO t1 VALUES ('0001-12-31 23:59:59.0');
CREATE FUNCTION FLOOR_SP(a DATETIME(6)) RETURNS DATETIME
BEGIN
RETURN
CASE
WHEN EXTRACT(MICROSECOND FROM a)=0 THEN a
ELSE TRUNCATE(a,0)
END;
END;
$$
CREATE FUNCTION CEILING_SP(a DATETIME(6)) RETURNS DATETIME
BEGIN
RETURN
CASE
WHEN TRUNCATE(a,0)=TIMESTAMP'9999-12-31 23:59:59' THEN a
WHEN EXTRACT(MICROSECOND FROM a)=0 THEN a
ELSE TRUNCATE(a,0)+INTERVAL 1 SECOND
END;
END;
$$
SELECT a, FLOOR(a), FLOOR_SP(a), FLOOR(a)=FLOOR_SP(a) FROM t1 ORDER BY a;
a FLOOR(a) FLOOR_SP(a) FLOOR(a)=FLOOR_SP(a)
0001-12-31 23:59:59.000000 0001-12-31 23:59:59 0001-12-31 23:59:59 1
0001-12-31 23:59:59.100000 0001-12-31 23:59:59 0001-12-31 23:59:59 1
0001-12-31 23:59:59.900000 0001-12-31 23:59:59 0001-12-31 23:59:59 1
0001-12-31 23:59:59.990000 0001-12-31 23:59:59 0001-12-31 23:59:59 1
0001-12-31 23:59:59.999000 0001-12-31 23:59:59 0001-12-31 23:59:59 1
0001-12-31 23:59:59.999900 0001-12-31 23:59:59 0001-12-31 23:59:59 1
0001-12-31 23:59:59.999990 0001-12-31 23:59:59 0001-12-31 23:59:59 1
0001-12-31 23:59:59.999999 0001-12-31 23:59:59 0001-12-31 23:59:59 1
0999-12-31 23:59:59.000000 0999-12-31 23:59:59 0999-12-31 23:59:59 1
0999-12-31 23:59:59.100000 0999-12-31 23:59:59 0999-12-31 23:59:59 1
0999-12-31 23:59:59.900000 0999-12-31 23:59:59 0999-12-31 23:59:59 1
0999-12-31 23:59:59.990000 0999-12-31 23:59:59 0999-12-31 23:59:59 1
0999-12-31 23:59:59.999000 0999-12-31 23:59:59 0999-12-31 23:59:59 1
0999-12-31 23:59:59.999900 0999-12-31 23:59:59 0999-12-31 23:59:59 1
0999-12-31 23:59:59.999990 0999-12-31 23:59:59 0999-12-31 23:59:59 1
0999-12-31 23:59:59.999999 0999-12-31 23:59:59 0999-12-31 23:59:59 1
9999-12-30 23:59:59.000000 9999-12-30 23:59:59 9999-12-30 23:59:59 1
9999-12-30 23:59:59.100000 9999-12-30 23:59:59 9999-12-30 23:59:59 1
9999-12-30 23:59:59.900000 9999-12-30 23:59:59 9999-12-30 23:59:59 1
9999-12-30 23:59:59.990000 9999-12-30 23:59:59 9999-12-30 23:59:59 1
9999-12-30 23:59:59.999000 9999-12-30 23:59:59 9999-12-30 23:59:59 1
9999-12-30 23:59:59.999900 9999-12-30 23:59:59 9999-12-30 23:59:59 1
9999-12-30 23:59:59.999990 9999-12-30 23:59:59 9999-12-30 23:59:59 1
9999-12-30 23:59:59.999999 9999-12-30 23:59:59 9999-12-30 23:59:59 1
9999-12-31 23:59:59.000000 9999-12-31 23:59:59 9999-12-31 23:59:59 1
9999-12-31 23:59:59.100000 9999-12-31 23:59:59 9999-12-31 23:59:59 1
9999-12-31 23:59:59.900000 9999-12-31 23:59:59 9999-12-31 23:59:59 1
9999-12-31 23:59:59.990000 9999-12-31 23:59:59 9999-12-31 23:59:59 1
9999-12-31 23:59:59.999000 9999-12-31 23:59:59 9999-12-31 23:59:59 1
9999-12-31 23:59:59.999900 9999-12-31 23:59:59 9999-12-31 23:59:59 1
9999-12-31 23:59:59.999990 9999-12-31 23:59:59 9999-12-31 23:59:59 1
9999-12-31 23:59:59.999999 9999-12-31 23:59:59 9999-12-31 23:59:59 1
SELECT a, CEILING(a), CEILING_SP(a), CEILING(a)=CEILING_SP(a) FROM t1 ORDER BY a;
a CEILING(a) CEILING_SP(a) CEILING(a)=CEILING_SP(a)
0001-12-31 23:59:59.000000 0001-12-31 23:59:59 0001-12-31 23:59:59 1
0001-12-31 23:59:59.100000 0002-01-01 00:00:00 0002-01-01 00:00:00 1
0001-12-31 23:59:59.900000 0002-01-01 00:00:00 0002-01-01 00:00:00 1
0001-12-31 23:59:59.990000 0002-01-01 00:00:00 0002-01-01 00:00:00 1
0001-12-31 23:59:59.999000 0002-01-01 00:00:00 0002-01-01 00:00:00 1
0001-12-31 23:59:59.999900 0002-01-01 00:00:00 0002-01-01 00:00:00 1
0001-12-31 23:59:59.999990 0002-01-01 00:00:00 0002-01-01 00:00:00 1
0001-12-31 23:59:59.999999 0002-01-01 00:00:00 0002-01-01 00:00:00 1
0999-12-31 23:59:59.000000 0999-12-31 23:59:59 0999-12-31 23:59:59 1
0999-12-31 23:59:59.100000 1000-01-01 00:00:00 1000-01-01 00:00:00 1
0999-12-31 23:59:59.900000 1000-01-01 00:00:00 1000-01-01 00:00:00 1
0999-12-31 23:59:59.990000 1000-01-01 00:00:00 1000-01-01 00:00:00 1
0999-12-31 23:59:59.999000 1000-01-01 00:00:00 1000-01-01 00:00:00 1
0999-12-31 23:59:59.999900 1000-01-01 00:00:00 1000-01-01 00:00:00 1
0999-12-31 23:59:59.999990 1000-01-01 00:00:00 1000-01-01 00:00:00 1
0999-12-31 23:59:59.999999 1000-01-01 00:00:00 1000-01-01 00:00:00 1
9999-12-30 23:59:59.000000 9999-12-30 23:59:59 9999-12-30 23:59:59 1
9999-12-30 23:59:59.100000 9999-12-31 00:00:00 9999-12-31 00:00:00 1
9999-12-30 23:59:59.900000 9999-12-31 00:00:00 9999-12-31 00:00:00 1
9999-12-30 23:59:59.990000 9999-12-31 00:00:00 9999-12-31 00:00:00 1
9999-12-30 23:59:59.999000 9999-12-31 00:00:00 9999-12-31 00:00:00 1
9999-12-30 23:59:59.999900 9999-12-31 00:00:00 9999-12-31 00:00:00 1
9999-12-30 23:59:59.999990 9999-12-31 00:00:00 9999-12-31 00:00:00 1
9999-12-30 23:59:59.999999 9999-12-31 00:00:00 9999-12-31 00:00:00 1
9999-12-31 23:59:59.000000 9999-12-31 23:59:59 9999-12-31 23:59:59 1
9999-12-31 23:59:59.100000 9999-12-31 23:59:59 9999-12-31 23:59:59 1
9999-12-31 23:59:59.900000 9999-12-31 23:59:59 9999-12-31 23:59:59 1
9999-12-31 23:59:59.990000 9999-12-31 23:59:59 9999-12-31 23:59:59 1
9999-12-31 23:59:59.999000 9999-12-31 23:59:59 9999-12-31 23:59:59 1
9999-12-31 23:59:59.999900 9999-12-31 23:59:59 9999-12-31 23:59:59 1
9999-12-31 23:59:59.999990 9999-12-31 23:59:59 9999-12-31 23:59:59 1
9999-12-31 23:59:59.999999 9999-12-31 23:59:59 9999-12-31 23:59:59 1
DROP FUNCTION FLOOR_SP;
DROP FUNCTION CEILING_SP;
DROP TABLE t1;
CREATE TABLE t1 (a DATETIME(6));
INSERT INTO t1 VALUES ('0000-00-00 23:59:59.999999');
INSERT INTO t1 VALUES ('0000-00-01 23:59:59.999999');
INSERT INTO t1 VALUES ('0000-01-01 23:59:59.999999');
INSERT INTO t1 VALUES ('0001-00-00 23:59:59.999999');
SELECT a, FLOOR(a), CEILING(a) FROM t1;
a FLOOR(a) CEILING(a)
0000-00-00 23:59:59.999999 0000-00-00 23:59:59 NULL
0000-00-01 23:59:59.999999 0000-00-01 23:59:59 NULL
0000-01-01 23:59:59.999999 0000-01-01 23:59:59 NULL
0001-00-00 23:59:59.999999 0001-00-00 23:59:59 NULL
Warnings:
Warning 1411 Incorrect date value: '0000-00-00' for function round(datetime)
Warning 1411 Incorrect date value: '0000-00-01' for function round(datetime)
Warning 1411 Incorrect date value: '0000-01-01' for function round(datetime)
Warning 1411 Incorrect date value: '0001-00-00' for function round(datetime)
DROP TABLE t1;
SET sql_mode=ALLOW_INVALID_DATES;
CREATE TABLE t1 (a DATETIME(6));
INSERT INTO t1 VALUES ('2001-02-28 23:59:59.999999');
INSERT INTO t1 VALUES ('2001-02-29 23:59:59.999999');
SELECT a, FLOOR(a), CEILING(a) FROM t1;
a FLOOR(a) CEILING(a)
2001-02-28 23:59:59.999999 2001-02-28 23:59:59 2001-03-01 00:00:00
2001-02-29 23:59:59.999999 2001-02-29 23:59:59 NULL
Warnings:
Warning 1411 Incorrect date value: '2001-02-29' for function round(datetime)
DROP TABLE t1;
SET sql_mode=DEFAULT;
#
# End of 10.4 tests
#
98 changes: 98 additions & 0 deletions mysql-test/main/type_datetime_hires.test
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,104 @@ SELECT ROUND(a) AS f FROM t1 GROUP BY a WITH ROLLUP;
DROP TABLE t1;


--echo #
--echo # MDEV-23311 CEILING() and FLOOR() convert temporal input to numbers, unlike ROUND() and TRUNCATE()
--echo #

CREATE TABLE t1 AS SELECT
FLOOR(TIMESTAMP'2001-01-01 00:00:00.999999'),
CEILING(TIMESTAMP'2001-01-01 00:00:00.999999');
SHOW CREATE TABLE t1;
DROP TABLE t1;

CREATE TABLE t1 (a DATETIME(6));

INSERT INTO t1 VALUES ('9999-12-31 23:59:59.999999');
INSERT INTO t1 VALUES ('9999-12-31 23:59:59.99999');
INSERT INTO t1 VALUES ('9999-12-31 23:59:59.9999');
INSERT INTO t1 VALUES ('9999-12-31 23:59:59.999');
INSERT INTO t1 VALUES ('9999-12-31 23:59:59.99');
INSERT INTO t1 VALUES ('9999-12-31 23:59:59.9');
INSERT INTO t1 VALUES ('9999-12-31 23:59:59.1');
INSERT INTO t1 VALUES ('9999-12-31 23:59:59.0');

INSERT INTO t1 VALUES ('9999-12-30 23:59:59.999999');
INSERT INTO t1 VALUES ('9999-12-30 23:59:59.99999');
INSERT INTO t1 VALUES ('9999-12-30 23:59:59.9999');
INSERT INTO t1 VALUES ('9999-12-30 23:59:59.999');
INSERT INTO t1 VALUES ('9999-12-30 23:59:59.99');
INSERT INTO t1 VALUES ('9999-12-30 23:59:59.9');
INSERT INTO t1 VALUES ('9999-12-30 23:59:59.1');
INSERT INTO t1 VALUES ('9999-12-30 23:59:59.0');

INSERT INTO t1 VALUES ('0999-12-31 23:59:59.999999');
INSERT INTO t1 VALUES ('0999-12-31 23:59:59.99999');
INSERT INTO t1 VALUES ('0999-12-31 23:59:59.9999');
INSERT INTO t1 VALUES ('0999-12-31 23:59:59.999');
INSERT INTO t1 VALUES ('0999-12-31 23:59:59.99');
INSERT INTO t1 VALUES ('0999-12-31 23:59:59.9');
INSERT INTO t1 VALUES ('0999-12-31 23:59:59.1');
INSERT INTO t1 VALUES ('0999-12-31 23:59:59.0');

INSERT INTO t1 VALUES ('0001-12-31 23:59:59.999999');
INSERT INTO t1 VALUES ('0001-12-31 23:59:59.99999');
INSERT INTO t1 VALUES ('0001-12-31 23:59:59.9999');
INSERT INTO t1 VALUES ('0001-12-31 23:59:59.999');
INSERT INTO t1 VALUES ('0001-12-31 23:59:59.99');
INSERT INTO t1 VALUES ('0001-12-31 23:59:59.9');
INSERT INTO t1 VALUES ('0001-12-31 23:59:59.1');
INSERT INTO t1 VALUES ('0001-12-31 23:59:59.0');


DELIMITER $$;
CREATE FUNCTION FLOOR_SP(a DATETIME(6)) RETURNS DATETIME
BEGIN
RETURN
CASE
WHEN EXTRACT(MICROSECOND FROM a)=0 THEN a
ELSE TRUNCATE(a,0)
END;
END;
$$
DELIMITER ;$$

DELIMITER $$;
CREATE FUNCTION CEILING_SP(a DATETIME(6)) RETURNS DATETIME
BEGIN
RETURN
CASE
WHEN TRUNCATE(a,0)=TIMESTAMP'9999-12-31 23:59:59' THEN a
WHEN EXTRACT(MICROSECOND FROM a)=0 THEN a
ELSE TRUNCATE(a,0)+INTERVAL 1 SECOND
END;
END;
$$
DELIMITER ;$$

SELECT a, FLOOR(a), FLOOR_SP(a), FLOOR(a)=FLOOR_SP(a) FROM t1 ORDER BY a;
SELECT a, CEILING(a), CEILING_SP(a), CEILING(a)=CEILING_SP(a) FROM t1 ORDER BY a;

DROP FUNCTION FLOOR_SP;
DROP FUNCTION CEILING_SP;

DROP TABLE t1;

CREATE TABLE t1 (a DATETIME(6));
INSERT INTO t1 VALUES ('0000-00-00 23:59:59.999999');
INSERT INTO t1 VALUES ('0000-00-01 23:59:59.999999');
INSERT INTO t1 VALUES ('0000-01-01 23:59:59.999999');
INSERT INTO t1 VALUES ('0001-00-00 23:59:59.999999');
SELECT a, FLOOR(a), CEILING(a) FROM t1;
DROP TABLE t1;

SET sql_mode=ALLOW_INVALID_DATES;
CREATE TABLE t1 (a DATETIME(6));
INSERT INTO t1 VALUES ('2001-02-28 23:59:59.999999');
INSERT INTO t1 VALUES ('2001-02-29 23:59:59.999999');
SELECT a, FLOOR(a), CEILING(a) FROM t1;
DROP TABLE t1;
SET sql_mode=DEFAULT;

--echo #
--echo # End of 10.4 tests
--echo #
Loading

0 comments on commit 5b3b53c

Please sign in to comment.