Skip to content

Commit 15b0792

Browse files
committed
Post-review cleanups for MDEV-20023 Implement Oracle TRUNC() function
1 parent 56cea82 commit 15b0792

File tree

7 files changed

+144
-40
lines changed

7 files changed

+144
-40
lines changed

mysql-test/suite/compat/oracle/r/func_trunc.result

Lines changed: 55 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,20 @@
22
#
33
# Simple test
44
#
5-
select trunc("2025-07-27 12:01:02.123");
6-
trunc("2025-07-27 12:01:02.123")
5+
select trunc('2025-07-27 12:01:02.123');
6+
trunc('2025-07-27 12:01:02.123')
77
2025-07-27
8-
select trunc("2025-07-27 12:01:02.123","YY");
9-
trunc("2025-07-27 12:01:02.123","YY")
8+
select trunc('2025-07-27 12:01:02.123','YY');
9+
trunc('2025-07-27 12:01:02.123','YY')
1010
2025-01-01
11-
select trunc("2025-07-27 12:01:02.123","MM");
12-
trunc("2025-07-27 12:01:02.123","MM")
11+
select trunc('2025-07-27 12:01:02.123','MM');
12+
trunc('2025-07-27 12:01:02.123','MM')
1313
2025-07-01
14-
select trunc("2025-07-27 12:01:02.123","DD");
15-
trunc("2025-07-27 12:01:02.123","DD")
14+
select trunc('2025-07-27 12:01:02.123','DD');
15+
trunc('2025-07-27 12:01:02.123','DD')
1616
2025-07-27
17-
select trunc("hello");
18-
trunc("hello")
17+
select trunc('hello');
18+
trunc('hello')
1919
NULL
2020
Warnings:
2121
Warning 1292 Incorrect datetime value: 'hello'
@@ -39,7 +39,7 @@ INSERT INTO t1 VALUES ('2021-11-12 00:23:12', '2021-11-12', '2021-11-12 00:23:12
3939
INSERT INTO t1 VALUES ('0000-09-02 00:00:00', '0000-09-02', '1980-09-02 00:00:00');
4040
INSERT INTO t1 VALUES ('9999-09-02', '9999-09-02', '1980-09-02');
4141
create table t2 (format varchar(5)) engine=aria;
42-
insert into t2 values ("DD"),("DDD"),("J"),("MM"),("MON"),("MONTH"),("RM"),("SYEAR"),("SYYYY"),("Y"),("YEAR"),("YY"),("YYY"),("YYYY"), ("ZZZ");
42+
insert into t2 values ('DD'),('DDD'),('J'),('MM'),('MON'),('MONTH'),('RM'),('SYEAR'),('SYYYY'),('Y'),('YEAR'),('YY'),('YYY'),('YYYY'), ('ZZZ');
4343
SELECT format,trunc(c2,format),trunc(c3,format),trunc(c4,format) from t2 straight_join t1;
4444
format trunc(c2,format) trunc(c3,format) trunc(c4,format)
4545
DD 2021-11-12 2021-11-12 2021-11-12
@@ -100,13 +100,18 @@ Warning 1292 Incorrect TRUNC value: 'ZZZ'
100100
#
101101
# Test wrong usage
102102
#
103-
select trunc('2021-11-12 00:23:12',"");
104-
trunc('2021-11-12 00:23:12',"")
103+
select trunc('2021-11-12 00:23:12','');
104+
trunc('2021-11-12 00:23:12','')
105105
NULL
106106
Warnings:
107107
Warning 1292 Incorrect TRUNC value: ''
108-
select trunc("","DD");
109-
trunc("","DD")
108+
select trunc('2021-11-12 00:23:12','ZZZZ');
109+
trunc('2021-11-12 00:23:12','ZZZZ')
110+
NULL
111+
Warnings:
112+
Warning 1292 Incorrect TRUNC value: 'ZZZZ'
113+
select trunc('','DD');
114+
trunc('','DD')
110115
NULL
111116
Warnings:
112117
Warning 1292 Incorrect datetime value: ''
@@ -120,3 +125,38 @@ Warning 1292 Incorrect datetime value: '1'
120125
select trunc(1,2,3);
121126
ERROR 42000: Incorrect parameter count in the call to native function 'trunc'
122127
drop table t1,t2;
128+
#
129+
# Fractional digits outside of the supported limit of 6 digits
130+
# are always truncated even if TIME_ROUND_FRACTIONAL is set.
131+
#
132+
SET sql_mode=TIME_ROUND_FRACTIONAL;
133+
SELECT trunc('2001-12-31 23:59:59.9999999','YYYY') AS c1;
134+
c1
135+
2001-01-01
136+
Warnings:
137+
Note 1292 Truncated incorrect datetime value: '2001-12-31 23:59:59.9999999'
138+
SELECT trunc('2001-12-31 23:59:59.9999999','MM') AS c1;
139+
c1
140+
2001-12-01
141+
Warnings:
142+
Note 1292 Truncated incorrect datetime value: '2001-12-31 23:59:59.9999999'
143+
SELECT trunc('2001-12-31 23:59:59.9999999','DD') AS c1;
144+
c1
145+
2001-12-31
146+
Warnings:
147+
Note 1292 Truncated incorrect datetime value: '2001-12-31 23:59:59.9999999'
148+
SET sql_mode=DEFAULT;
149+
#
150+
# TIME argument is converted to DATE using CURRENT_DATE
151+
#
152+
SET timestamp=unix_timestamp('2001-12-31 10:00:00');
153+
SELECT trunc(time'24:00:00','YYYY');
154+
trunc(time'24:00:00','YYYY')
155+
2002-01-01
156+
SELECT trunc(time'24:00:00','MM');
157+
trunc(time'24:00:00','MM')
158+
2002-01-01
159+
SELECT trunc(time'24:00:00','DD');
160+
trunc(time'24:00:00','DD')
161+
2002-01-01
162+
SET timestamp=DEFAULT;
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#
2+
# MDEV-20023 Implement Oracle TRUNC() function
3+
#
4+
SET NAMES utf8mb4, @@character_set_connection=ucs2;
5+
CREATE TABLE t1 (dt DATETIME);
6+
INSERT INTO t1 VALUES ('2001-02-03 10:20:30');
7+
SELECT trunc(dt, 'YYYY') FROM t1;
8+
trunc(dt, 'YYYY')
9+
2001-01-01
10+
SELECT trunc(dt, 'MM') FROM t1;
11+
trunc(dt, 'MM')
12+
2001-02-01
13+
SELECT trunc(dt, 'DD') FROM t1;
14+
trunc(dt, 'DD')
15+
2001-02-03
16+
CREATE TABLE t2 (fmt VARCHAR(32) CHARACTER SET ucs2);
17+
INSERT INTO t2 VALUES ('YYYY'),('MM'),('DD');
18+
SELECT trunc(dt, fmt) FROM t1, t2;
19+
trunc(dt, fmt)
20+
2001-01-01
21+
2001-02-01
22+
2001-02-03
23+
DROP TABLE t2;
24+
DROP TABLE t1;

mysql-test/suite/compat/oracle/t/func_trunc.test

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44
--echo # Simple test
55
--echo #
66

7-
select trunc("2025-07-27 12:01:02.123");
8-
select trunc("2025-07-27 12:01:02.123","YY");
9-
select trunc("2025-07-27 12:01:02.123","MM");
10-
select trunc("2025-07-27 12:01:02.123","DD");
7+
select trunc('2025-07-27 12:01:02.123');
8+
select trunc('2025-07-27 12:01:02.123','YY');
9+
select trunc('2025-07-27 12:01:02.123','MM');
10+
select trunc('2025-07-27 12:01:02.123','DD');
1111

12-
select trunc("hello");
12+
select trunc('hello');
1313
select trunc(1);
1414

1515
--echo # Ensure that trunc table name and column can still be used
@@ -29,20 +29,42 @@ INSERT INTO t1 VALUES ('0000-09-02 00:00:00', '0000-09-02', '1980-09-02 00:00:00
2929
INSERT INTO t1 VALUES ('9999-09-02', '9999-09-02', '1980-09-02');
3030

3131
create table t2 (format varchar(5)) engine=aria;
32-
insert into t2 values ("DD"),("DDD"),("J"),("MM"),("MON"),("MONTH"),("RM"),("SYEAR"),("SYYYY"),("Y"),("YEAR"),("YY"),("YYY"),("YYYY"), ("ZZZ");
32+
insert into t2 values ('DD'),('DDD'),('J'),('MM'),('MON'),('MONTH'),('RM'),('SYEAR'),('SYYYY'),('Y'),('YEAR'),('YY'),('YYY'),('YYYY'), ('ZZZ');
3333

3434
SELECT format,trunc(c2,format),trunc(c3,format),trunc(c4,format) from t2 straight_join t1;
3535

3636
--echo #
3737
--echo # Test wrong usage
3838
--echo #
3939

40-
select trunc('2021-11-12 00:23:12',"");
41-
select trunc("","DD");
40+
select trunc('2021-11-12 00:23:12','');
41+
select trunc('2021-11-12 00:23:12','ZZZZ');
42+
select trunc('','DD');
4243
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
4344
select trunc();
4445
select trunc(1);
4546
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
4647
select trunc(1,2,3);
4748

4849
drop table t1,t2;
50+
51+
--echo #
52+
--echo # Fractional digits outside of the supported limit of 6 digits
53+
--echo # are always truncated even if TIME_ROUND_FRACTIONAL is set.
54+
--echo #
55+
56+
SET sql_mode=TIME_ROUND_FRACTIONAL;
57+
SELECT trunc('2001-12-31 23:59:59.9999999','YYYY') AS c1;
58+
SELECT trunc('2001-12-31 23:59:59.9999999','MM') AS c1;
59+
SELECT trunc('2001-12-31 23:59:59.9999999','DD') AS c1;
60+
SET sql_mode=DEFAULT;
61+
62+
--echo #
63+
--echo # TIME argument is converted to DATE using CURRENT_DATE
64+
--echo #
65+
66+
SET timestamp=unix_timestamp('2001-12-31 10:00:00');
67+
SELECT trunc(time'24:00:00','YYYY');
68+
SELECT trunc(time'24:00:00','MM');
69+
SELECT trunc(time'24:00:00','DD');
70+
SET timestamp=DEFAULT;
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
--source include/have_ucs2.inc
2+
3+
--echo #
4+
--echo # MDEV-20023 Implement Oracle TRUNC() function
5+
--echo #
6+
7+
SET NAMES utf8mb4, @@character_set_connection=ucs2;
8+
9+
CREATE TABLE t1 (dt DATETIME);
10+
INSERT INTO t1 VALUES ('2001-02-03 10:20:30');
11+
# Testing constant format
12+
SELECT trunc(dt, 'YYYY') FROM t1;
13+
SELECT trunc(dt, 'MM') FROM t1;
14+
SELECT trunc(dt, 'DD') FROM t1;
15+
# Testing non-constant format
16+
CREATE TABLE t2 (fmt VARCHAR(32) CHARACTER SET ucs2);
17+
INSERT INTO t2 VALUES ('YYYY'),('MM'),('DD');
18+
SELECT trunc(dt, fmt) FROM t1, t2;
19+
DROP TABLE t2;
20+
DROP TABLE t1;

sql/item_timefunc.cc

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4084,19 +4084,15 @@ static struct TRUNC_FORMAT trunc_options[]=
40844084

40854085

40864086
Item_func_trunc::enum_trunc
4087-
Item_func_trunc::get_trunc_option(String *format_arg)
4087+
Item_func_trunc::get_trunc_option(const LEX_CSTRING format)
40884088
{
4089-
uint low=0, high= array_elements(trunc_options);
4090-
const char *format= format_arg->ptr();
4091-
size_t format_length= format_arg->length();
4089+
uint low=0, high= array_elements(trunc_options) - 1;
40924090

40934091
/* Use binary search to find the format */
40944092
do
40954093
{
40964094
uint mid= (low+high)/2;
4097-
int cmp= my_charset_latin1.strnncoll(format, format_length,
4098-
trunc_options[mid].name.str,
4099-
trunc_options[mid].name.length);
4095+
int cmp= my_charset_latin1.strnncoll(format, trunc_options[mid].name);
41004096
if (!cmp)
41014097
return trunc_options[mid].format;
41024098
if (cmp > 0)
@@ -4114,9 +4110,9 @@ bool Item_func_trunc::fix_length_and_dec(THD *thd)
41144110
if (args[1]->basic_const_item())
41154111
{
41164112
String tmp, *res;
4117-
if ((res= args[1]->val_str(&tmp)))
4113+
if ((res= args[1]->val_str_ascii(&tmp)))
41184114
{
4119-
const_format= get_trunc_option(res);
4115+
const_format= get_trunc_option(res->to_lex_cstring());
41204116
if (const_format == TRUNC_IMPOSSIBLE)
41214117
const_format= TRUNC_UNINIT; // Error handling in get_date()
41224118
}
@@ -4128,17 +4124,18 @@ bool Item_func_trunc::fix_length_and_dec(THD *thd)
41284124
bool Item_func_trunc::get_date(THD *thd, MYSQL_TIME *ltime,
41294125
date_mode_t fuzzydate)
41304126
{
4131-
Datetime::Options opt(TIME_NO_ZEROS, thd);
4127+
Date::Options opt(TIME_NO_ZEROS, TIME_FRAC_TRUNCATE);
41324128
enum_trunc format= TRUNC_IMPOSSIBLE;
4133-
if (Datetime(thd, args[0], opt).copy_to_mysql_time(ltime))
4134-
goto error;
4129+
Date *d= new(ltime) Date(thd, args[0], opt);
4130+
if ((null_value= !d->is_valid_date()))
4131+
return true;
41354132
if (const_format != TRUNC_UNINIT)
41364133
format= const_format;
41374134
else
41384135
{
41394136
String tmp, *res;
4140-
if ((res= args[1]->val_str(&tmp)))
4141-
format= get_trunc_option(res);
4137+
if ((res= args[1]->val_str_ascii(&tmp)))
4138+
format= get_trunc_option(res->to_lex_cstring());
41424139
if (format == TRUNC_IMPOSSIBLE)
41434140
{
41444141
thd->push_warning_wrong_value(Sql_condition::WARN_LEVEL_WARN, "TRUNC",
@@ -4161,8 +4158,6 @@ bool Item_func_trunc::get_date(THD *thd, MYSQL_TIME *ltime,
41614158
ltime->day= 1;
41624159
/* fall through */
41634160
case TRUNC_DAY:
4164-
ltime->hour= ltime->minute= ltime->second= 0;
4165-
ltime->second_part= 0;
41664161
break;
41674162
}
41684163
return false;

sql/item_timefunc.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2155,7 +2155,7 @@ class Item_func_trunc :public Item_datefunc
21552155
bool error_given;
21562156
bool check_arguments() const override
21572157
{ return args[0]->check_type_can_return_date(func_name_cstring()); }
2158-
enum_trunc get_trunc_option(String *format);
2158+
enum_trunc get_trunc_option(const LEX_CSTRING format);
21592159

21602160
public:
21612161
Item_func_trunc(THD *thd, Item *a, Item *b):

sql/sql_type.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2270,6 +2270,9 @@ class Date: public Temporal_with_date
22702270
class Options: public Temporal_with_date::Options
22712271
{
22722272
public:
2273+
Options(date_conv_mode_t dmode, time_round_mode_t rmode)
2274+
:Temporal_with_date::Options(dmode, rmode)
2275+
{ }
22732276
explicit Options(date_conv_mode_t fuzzydate)
22742277
:Temporal_with_date::Options(fuzzydate, TIME_FRAC_TRUNCATE)
22752278
{ }

0 commit comments

Comments
 (0)