Add timestampadd/timestampdiff function (#2725)

This commit is contained in:
HangyuanLiu
2020-01-15 21:47:07 +08:00
committed by ZHAO Chun
parent 8ea5907252
commit 0ddca59d36
18 changed files with 793 additions and 64 deletions

View File

@ -351,6 +351,106 @@ DateTimeVal TimestampFunctions::timestamp_time_op(
return new_ts_val;
}
BigIntVal TimestampFunctions::years_diff(
FunctionContext* ctx, const DateTimeVal& ts_val1, const DateTimeVal& ts_val2) {
return timestamp_diff<YEAR>(ctx, ts_val1, ts_val2);
}
BigIntVal TimestampFunctions::months_diff(
FunctionContext* ctx, const DateTimeVal& ts_val1, const DateTimeVal& ts_val2) {
return timestamp_diff<MONTH>(ctx, ts_val1, ts_val2);
}
BigIntVal TimestampFunctions::weeks_diff(
FunctionContext* ctx, const DateTimeVal& ts_val1, const DateTimeVal& ts_val2) {
return timestamp_diff<WEEK>(ctx, ts_val1, ts_val2);
}
BigIntVal TimestampFunctions::days_diff(
FunctionContext* ctx, const DateTimeVal& ts_val1, const DateTimeVal& ts_val2) {
return timestamp_diff<DAY>(ctx, ts_val1, ts_val2);
}
BigIntVal TimestampFunctions::hours_diff(
FunctionContext* ctx, const DateTimeVal& ts_val1, const DateTimeVal& ts_val2) {
return timestamp_diff<HOUR>(ctx, ts_val1, ts_val2);
}
BigIntVal TimestampFunctions::minutes_diff(
FunctionContext* ctx, const DateTimeVal& ts_val1, const DateTimeVal& ts_val2) {
return timestamp_diff<MINUTE>(ctx, ts_val1, ts_val2);
}
BigIntVal TimestampFunctions::seconds_diff(
FunctionContext* ctx, const DateTimeVal& ts_val1, const DateTimeVal& ts_val2) {
return timestamp_diff<SECOND>(ctx, ts_val1, ts_val2);
}
template <TimeUnit unit>
BigIntVal TimestampFunctions::timestamp_diff(FunctionContext* ctx, const DateTimeVal& ts_val2, const DateTimeVal& ts_val1) {
if (ts_val1.is_null || ts_val2.is_null) {
return BigIntVal::null();
}
DateTimeValue ts_value1 = DateTimeValue::from_datetime_val(ts_val1);
DateTimeValue ts_value2 = DateTimeValue::from_datetime_val(ts_val2);
switch (unit) {
case YEAR: {
int year = (ts_value2.year() - ts_value1.year());
if (year >= 0) {
year -= (ts_value2.to_int64() % 10000000000 - ts_value1.to_int64() % 10000000000) < 0;
} else {
year += (ts_value2.to_int64() % 10000000000 - ts_value1.to_int64() % 10000000000) > 0;
}
return year;
}
case MONTH: {
int month = (ts_value2.year() - ts_value1.year()) * 12 + (ts_value2.month() - ts_value1.month());
if (month >= 0) {
month -= (ts_value2.to_int64() % 100000000 - ts_value1.to_int64() % 100000000) < 0;
} else {
month += (ts_value2.to_int64() % 100000000 - ts_value1.to_int64() % 100000000) > 0;
}
return month;
}
case WEEK: {
int day = ts_value2.daynr() - ts_value1.daynr();
if (day >= 0) {
day -= ts_value2.time_part_diff(ts_value1) < 0;
} else {
day += ts_value2.time_part_diff(ts_value1) > 0;
}
return day / 7;
}
case DAY: {
int day = ts_value2.daynr() - ts_value1.daynr();
if (day >= 0) {
day -= ts_value2.time_part_diff(ts_value1) < 0;
} else {
day += ts_value2.time_part_diff(ts_value1) > 0;
}
return day;
}
case HOUR: {
int64_t second = ts_value2.second_diff(ts_value1);
int64_t hour = second / 60 / 60;
return hour;
}
case MINUTE: {
int64_t second = ts_value2.second_diff(ts_value1);
int64_t minute = second / 60;
return minute;
}
case SECOND: {
int64_t second = ts_value2.second_diff(ts_value1);
return second;
}
default:
return BigIntVal::null();
}
}
StringVal TimestampFunctions::date_format(
FunctionContext* ctx, const DateTimeVal& ts_val, const StringVal& format) {
if (ts_val.is_null || format.is_null) {

View File

@ -130,6 +130,25 @@ public:
static doris_udf::StringVal day_name(
doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val);
// timestamp function
template <TimeUnit unit>
static doris_udf::BigIntVal timestamp_diff(
doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val1, const doris_udf::DateTimeVal& ts_val2);
static doris_udf::BigIntVal years_diff(
doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val1, const doris_udf::DateTimeVal& ts_val2);
static doris_udf::BigIntVal months_diff(
doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val1, const doris_udf::DateTimeVal& ts_val2);
static doris_udf::BigIntVal weeks_diff(
doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val1, const doris_udf::DateTimeVal& ts_val2);
static doris_udf::BigIntVal days_diff(
doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val1, const doris_udf::DateTimeVal& ts_val2);
static doris_udf::BigIntVal hours_diff(
doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val1, const doris_udf::DateTimeVal& ts_val2);
static doris_udf::BigIntVal minutes_diff(
doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val1, const doris_udf::DateTimeVal& ts_val2);
static doris_udf::BigIntVal seconds_diff(
doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& ts_val1, const doris_udf::DateTimeVal& ts_val2);
// TimeZone correlation functions.
static doris_udf::DateTimeVal timestamp(
doris_udf::FunctionContext* ctx, const doris_udf::DateTimeVal& val);

View File

@ -446,6 +446,12 @@ public:
return day_diff * 3600 * 24 + time_diff;
}
int64_t time_part_diff(const DateTimeValue& rhs) const {
int time_diff = (hour() * 3600 + minute() * 60 + second())
- (rhs.hour() * 3600 + rhs.minute() * 60 + rhs.second());
return time_diff;
}
void set_type(int type);
static const char* _s_llvm_class_name;

View File

@ -122,6 +122,57 @@ TEST_F(TimestampFunctionsTest, convert_tz_test) {
ASSERT_EQ(20190806013857, dt3.to_int64());
}
TEST_F(TimestampFunctionsTest, timestampdiff_test) {
doris_udf::FunctionContext *context = new doris_udf::FunctionContext();
DateTimeValue dt1(20120824000001);
doris_udf::DateTimeVal tv1;
dt1.to_datetime_val(&tv1);
DateTimeValue dt2(20120830000000);
doris_udf::DateTimeVal tv2;
dt2.to_datetime_val(&tv2);
//YEAR
ASSERT_EQ(0, TimestampFunctions::years_diff(context, tv2, tv1).val);
DateTimeValue dt_year(20100930000000);
doris_udf::DateTimeVal tv_year;
dt_year.to_datetime_val(&tv_year);
ASSERT_EQ(-1, TimestampFunctions::years_diff(context, tv_year, tv1).val);
//MONTH
ASSERT_EQ(0, TimestampFunctions::months_diff(context, tv2, tv1).val);
DateTimeValue dt3(20120924000000);
doris_udf::DateTimeVal tv3;
dt3.to_datetime_val(&tv3);
ASSERT_EQ(0, TimestampFunctions::months_diff(context, tv3, tv1).val);
DateTimeValue dt_month(20120631000000);
doris_udf::DateTimeVal tv_month;
dt_month.to_datetime_val(&tv_month);
ASSERT_EQ(-1, TimestampFunctions::months_diff(context, tv_month, tv1).val);
//WEEK
ASSERT_EQ(0, TimestampFunctions::weeks_diff(context, tv2, tv1).val);
//DAY
ASSERT_EQ(5, TimestampFunctions::days_diff(context, tv2, tv1).val);
DateTimeValue dt4(20120830000001);
doris_udf::DateTimeVal tv4;
dt4.to_datetime_val(&tv4);
ASSERT_EQ(6, TimestampFunctions::days_diff(context, tv4, tv1).val);
DateTimeValue dt5(20120901000001);
doris_udf::DateTimeVal tv5;
dt5.to_datetime_val(&tv5);
ASSERT_EQ(8, TimestampFunctions::days_diff(context, tv5, tv1).val);
DateTimeValue dt_day(20120823000005);
doris_udf::DateTimeVal tv_day;
dt_day.to_datetime_val(&tv_day);
ASSERT_EQ(0, TimestampFunctions::days_diff(context, tv_day, tv1).val);
//HOUR
ASSERT_EQ(143, TimestampFunctions::hours_diff(context, tv2, tv1).val);
//MINUTE
ASSERT_EQ(8639, TimestampFunctions::minutes_diff(context, tv2, tv1).val);
//SECOND
ASSERT_EQ(518399, TimestampFunctions::seconds_diff(context, tv2, tv1).val);
}
}
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);

View File

@ -0,0 +1,42 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
# hour
## description
### Syntax
`INT HOUR(DATETIME date)`
获得日期中的小时的信息,返回值范围从0-23。
参数为Date或者Datetime类型
## example
```
mysql> select hour('2018-12-31 23:59:59');
+-----------------------------+
| hour('2018-12-31 23:59:59') |
+-----------------------------+
| 23 |
+-----------------------------+
```
##keyword
HOUR

View File

@ -0,0 +1,42 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
# minute
## description
### Syntax
`INT MINUTE(DATETIME date)`
获得日期中的分钟的信息,返回值范围从0-59。
参数为Date或者Datetime类型
## example
```
mysql> select minute('2018-12-31 23:59:59');
+-----------------------------+
| minute('2018-12-31 23:59:59') |
+-----------------------------+
| 59 |
+-----------------------------+
```
##keyword
MINUTE

View File

@ -0,0 +1,42 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
# second
## description
### Syntax
`INT SECOND(DATETIME date)`
获得日期中的秒的信息,返回值范围从0-59。
参数为Date或者Datetime类型
## example
```
mysql> select second('2018-12-31 23:59:59');
+-----------------------------+
| second('2018-12-31 23:59:59') |
+-----------------------------+
| 59 |
+-----------------------------+
```
##keyword
SECOND

View File

@ -0,0 +1,52 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
# timestampadd
## description
### Syntax
`DATETIME TIMESTAMPADD(unit, interval, DATETIME datetime_expr)`
将整数表达式间隔添加到日期或日期时间表达式datetime_expr中。
interval的单位由unit参数给出,它应该是下列值之一:
SECOND, MINUTE, HOUR, DAY, WEEK, MONTH, or YEAR。
## example
```
mysql> SELECT TIMESTAMPADD(MINUTE,1,'2019-01-02');
+------------------------------------------------+
| timestampadd(MINUTE, 1, '2019-01-02 00:00:00') |
+------------------------------------------------+
| 2019-01-02 00:01:00 |
+------------------------------------------------+
mysql> SELECT TIMESTAMPADD(WEEK,1,'2019-01-02');
+----------------------------------------------+
| timestampadd(WEEK, 1, '2019-01-02 00:00:00') |
+----------------------------------------------+
| 2019-01-09 00:00:00 |
+----------------------------------------------+
```
##keyword
TIMESTAMPADD

View File

@ -0,0 +1,60 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
# timestampdiff
## description
### Syntax
`INT TIMESTAMPDIFF(unit,DATETIME datetime_expr1, DATETIME datetime_expr2)`
返回datetime_expr2−datetime_expr1,其中datetime_expr1和datetime_expr2是日期或日期时间表达式。
结果(整数)的单位由unit参数给出。interval的单位由unit参数给出,它应该是下列值之一:
SECOND, MINUTE, HOUR, DAY, WEEK, MONTH, or YEAR。
## example
```
MySQL> SELECT TIMESTAMPDIFF(MONTH,'2003-02-01','2003-05-01');
+--------------------------------------------------------------------+
| timestampdiff(MONTH, '2003-02-01 00:00:00', '2003-05-01 00:00:00') |
+--------------------------------------------------------------------+
| 3 |
+--------------------------------------------------------------------+
MySQL> SELECT TIMESTAMPDIFF(YEAR,'2002-05-01','2001-01-01');
+-------------------------------------------------------------------+
| timestampdiff(YEAR, '2002-05-01 00:00:00', '2001-01-01 00:00:00') |
+-------------------------------------------------------------------+
| -1 |
+-------------------------------------------------------------------+
MySQL> SELECT TIMESTAMPDIFF(MINUTE,'2003-02-01','2003-05-01 12:05:55');
+---------------------------------------------------------------------+
| timestampdiff(MINUTE, '2003-02-01 00:00:00', '2003-05-01 12:05:55') |
+---------------------------------------------------------------------+
| 128885 |
+---------------------------------------------------------------------+
```
##keyword
TIMESTAMPDIFF

View File

@ -0,0 +1,41 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
# hour
## description
### Syntax
`INT HOUR(DATETIME date)`
Returns hour information in the time type, ranging from 0,23
The parameter is Date or Datetime type
## example
```
mysql> select hour('2018-12-31 23:59:59');
+-----------------------------+
| hour('2018-12-31 23:59:59') |
+-----------------------------+
| 23 |
+-----------------------------+
```
##keyword
HOUR

View File

@ -0,0 +1,41 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
# minute
## description
### Syntax
`INT MINUTE(DATETIME date)`
Returns minute information in the time type, ranging from 0,59
The parameter is Date or Datetime type
## example
```
mysql> select minute('2018-12-31 23:59:59');
+-----------------------------+
| minute('2018-12-31 23:59:59') |
+-----------------------------+
| 59 |
+-----------------------------+
```
##keyword
MINUTE

View File

@ -0,0 +1,41 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
# second
## description
### Syntax
`INT SECOND(DATETIME date)`
Returns second information in the time type, ranging from 0,59
The parameter is Date or Datetime type
## example
```
mysql> select second('2018-12-31 23:59:59');
+-----------------------------+
| second('2018-12-31 23:59:59') |
+-----------------------------+
| 59 |
+-----------------------------+
```
##keyword
SECOND

View File

@ -0,0 +1,51 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
# timestampadd
## description
### Syntax
`DATETIME TIMESTAMPADD(unit, interval, DATETIME datetime_expr)`
Adds the integer expression interval to the date or datetime expression datetime_expr.
The unit for interval is given by the unit argument, which should be one of the following values:
SECOND, MINUTE, HOUR, DAY, WEEK, MONTH, or YEAR.
## example
```
mysql> SELECT TIMESTAMPADD(MINUTE,1,'2019-01-02');
+------------------------------------------------+
| timestampadd(MINUTE, 1, '2019-01-02 00:00:00') |
+------------------------------------------------+
| 2019-01-02 00:01:00 |
+------------------------------------------------+
mysql> SELECT TIMESTAMPADD(WEEK,1,'2019-01-02');
+----------------------------------------------+
| timestampadd(WEEK, 1, '2019-01-02 00:00:00') |
+----------------------------------------------+
| 2019-01-09 00:00:00 |
+----------------------------------------------+
```
##keyword
TIMESTAMPADD

View File

@ -0,0 +1,60 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
# timestampdiff
## description
### Syntax
`INT TIMESTAMPDIFF(unit,DATETIME datetime_expr1, DATETIME datetime_expr2)`
Returns datetime_expr2 − datetime_expr1, where datetime_expr1 and datetime_expr2 are date or datetime expressions.
The unit for the result (an integer) is given by the unit argument.
The legal values for unit are the same as those listed in the description of the TIMESTAMPADD() function.
## example
```
MySQL> SELECT TIMESTAMPDIFF(MONTH,'2003-02-01','2003-05-01');
+--------------------------------------------------------------------+
| timestampdiff(MONTH, '2003-02-01 00:00:00', '2003-05-01 00:00:00') |
+--------------------------------------------------------------------+
| 3 |
+--------------------------------------------------------------------+
MySQL> SELECT TIMESTAMPDIFF(YEAR,'2002-05-01','2001-01-01');
+-------------------------------------------------------------------+
| timestampdiff(YEAR, '2002-05-01 00:00:00', '2001-01-01 00:00:00') |
+-------------------------------------------------------------------+
| -1 |
+-------------------------------------------------------------------+
MySQL> SELECT TIMESTAMPDIFF(MINUTE,'2003-02-01','2003-05-01 12:05:55');
+---------------------------------------------------------------------+
| timestampdiff(MINUTE, '2003-02-01 00:00:00', '2003-05-01 12:05:55') |
+---------------------------------------------------------------------+
| 128885 |
+---------------------------------------------------------------------+
```
##keyword
TIMESTAMPDIFF

View File

@ -195,12 +195,12 @@ terminal String KW_ADD, KW_ADMIN, KW_AFTER, KW_AGGREGATE, KW_ALL, KW_ALTER, KW_A
KW_CANCEL, KW_CASE, KW_CAST, KW_CHAIN, KW_CHAR, KW_CHARSET, KW_CLUSTER, KW_CLUSTERS,
KW_COLLATE, KW_COLLATION, KW_COLUMN, KW_COLUMNS, KW_COMMENT, KW_COMMIT, KW_COMMITTED,
KW_CONFIG, KW_CONNECTION, KW_CONNECTION_ID, KW_CONSISTENT, KW_COUNT, KW_CREATE, KW_CROSS, KW_CURRENT, KW_CURRENT_USER,
KW_DATA, KW_DATABASE, KW_DATABASES, KW_DATE, KW_DATETIME, KW_TIME, KW_DECIMAL, KW_DECOMMISSION, KW_DEFAULT, KW_DESC, KW_DESCRIBE,
KW_DATA, KW_DATABASE, KW_DATABASES, KW_DATE, KW_DATETIME, KW_DAY, KW_DECIMAL, KW_DECOMMISSION, KW_DEFAULT, KW_DESC, KW_DESCRIBE,
KW_DELETE, KW_DISTINCT, KW_DISTINCTPC, KW_DISTINCTPCSA, KW_DISTRIBUTED, KW_DISTRIBUTION, KW_DYNAMIC, KW_BUCKETS, KW_DIV, KW_DOUBLE, KW_DROP, KW_DROPP, KW_DUPLICATE,
KW_ELSE, KW_END, KW_ENGINE, KW_ENGINES, KW_ENTER, KW_ERRORS, KW_EVENTS, KW_EXISTS, KW_EXPORT, KW_EXTERNAL, KW_EXTRACT,
KW_FALSE, KW_FOLLOWER, KW_FOLLOWING, KW_FREE, KW_FROM, KW_FILE, KW_FIRST, KW_FLOAT, KW_FOR, KW_FORMAT, KW_FRONTEND, KW_FRONTENDS, KW_FULL, KW_FUNCTION,
KW_GLOBAL, KW_GRANT, KW_GRANTS, KW_GROUP,
KW_HASH, KW_HAVING, KW_HELP,KW_HLL, KW_HLL_UNION, KW_HUB,
KW_HASH, KW_HAVING, KW_HELP,KW_HLL, KW_HLL_UNION, KW_HOUR, KW_HUB,
KW_IDENTIFIED, KW_IF, KW_IN, KW_INDEX, KW_INDEXES, KW_INFILE,
KW_INNER, KW_INSERT, KW_INT, KW_INTERMEDIATE, KW_INTERVAL, KW_INTO, KW_IS, KW_ISNULL, KW_ISOLATION,
KW_JOIN,
@ -208,7 +208,7 @@ terminal String KW_ADD, KW_ADMIN, KW_AFTER, KW_AGGREGATE, KW_ALL, KW_ALTER, KW_A
KW_LABEL, KW_LARGEINT, KW_LAST, KW_LEFT, KW_LESS, KW_LEVEL, KW_LIKE, KW_LIMIT, KW_LINK, KW_LOAD,
KW_ROUTINE, KW_PAUSE, KW_RESUME, KW_STOP, KW_TASK,
KW_LOCAL, KW_LOCATION,
KW_MAX, KW_MAX_VALUE, KW_MERGE, KW_MIN, KW_MIGRATE, KW_MIGRATIONS, KW_MODIFY,
KW_MAX, KW_MAX_VALUE, KW_MERGE, KW_MIN, KW_MINUTE, KW_MIGRATE, KW_MIGRATIONS, KW_MODIFY, KW_MONTH,
KW_NAME, KW_NAMES, KW_NEGATIVE, KW_NO, KW_NOT, KW_NULL, KW_NULLS,
KW_OBSERVER, KW_OFFSET, KW_ON, KW_ONLY, KW_OPEN, KW_OR, KW_PIPE, KW_ORDER, KW_OUTER, KW_OVER,
KW_PARTITION, KW_PARTITIONS, KW_PATH, KW_PRECEDING,
@ -219,14 +219,15 @@ terminal String KW_ADD, KW_ADMIN, KW_AFTER, KW_AGGREGATE, KW_ALL, KW_ALTER, KW_A
KW_RANDOM, KW_RANGE, KW_READ, KW_RECOVER, KW_REGEXP, KW_RELEASE, KW_RENAME,
KW_REPAIR, KW_REPEATABLE, KW_REPOSITORY, KW_REPOSITORIES, KW_REPLACE, KW_REPLACE_IF_NOT_NULL, KW_REPLICA, KW_RESOURCE, KW_RESTORE, KW_RETURNS, KW_REVOKE,
KW_RIGHT, KW_ROLE, KW_ROLES, KW_ROLLBACK, KW_ROLLUP, KW_ROW, KW_ROWS,
KW_SCHEMAS, KW_SELECT, KW_SEMI, KW_SERIALIZABLE, KW_SESSION, KW_SET, KW_SHOW,
KW_SCHEMAS, KW_SECOND, KW_SELECT, KW_SEMI, KW_SERIALIZABLE, KW_SESSION, KW_SET, KW_SHOW,
KW_SMALLINT, KW_SNAPSHOT, KW_SONAME, KW_SPLIT, KW_START, KW_STATUS, KW_STORAGE, KW_STRING,
KW_SUM, KW_SUPERUSER, KW_SYNC, KW_SYSTEM,
KW_TABLE, KW_TABLES, KW_TABLET, KW_TERMINATED, KW_THAN, KW_THEN, KW_TIMESTAMP, KW_TINYINT,
KW_TABLE, KW_TABLES, KW_TABLET, KW_TERMINATED, KW_THAN, KW_THEN, KW_TIME, KW_TIMESTAMP, KW_TINYINT,
KW_TO, KW_TRANSACTION, KW_TRIGGERS, KW_TRIM, KW_TRUE, KW_TRUNCATE, KW_TYPE, KW_TYPES,
KW_UNCOMMITTED, KW_UNBOUNDED, KW_UNION, KW_UNIQUE, KW_UNSIGNED, KW_USE, KW_USER, KW_USING,
KW_VALUE, KW_VALUES, KW_VARCHAR, KW_VARIABLES, KW_VIEW, KW_MATERIALIZED,
KW_WARNINGS, KW_WHEN, KW_WHITELIST, KW_WHERE, KW_WITH, KW_WORK, KW_WRITE;
KW_WARNINGS, KW_WEEK, KW_WHEN, KW_WHITELIST, KW_WHERE, KW_WITH, KW_WORK, KW_WRITE,
KW_YEAR;
terminal COMMA, DOT, DOTDOTDOT, AT, STAR, LPAREN, RPAREN, SEMICOLON, LBRACKET, RBRACKET, DIVIDE, MOD, ADD, SUBTRACT;
terminal BITAND, BITOR, BITXOR, BITNOT;
@ -3783,6 +3784,10 @@ timestamp_arithmetic_expr ::=
RESULT = new TimestampArithmeticExpr(functionName.getFunction(), l.get(0), v, u);
:}
| function_name:functionName LPAREN keyword:u COMMA expr:e1 COMMA expr:e2 RPAREN
{:
RESULT = new TimestampArithmeticExpr(functionName.getFunction(), e2, e1, u);
:}
;
literal ::=
@ -4352,6 +4357,20 @@ keyword ::=
{: RESULT = id; :}
| KW_DYNAMIC:id
{: RESULT = id; :}
| KW_YEAR:id
{: RESULT = id; :}
| KW_MONTH:id
{: RESULT = id; :}
| KW_WEEK:id
{: RESULT = id; :}
| KW_DAY:id
{: RESULT = id; :}
| KW_HOUR:id
{: RESULT = id; :}
| KW_MINUTE:id
{: RESULT = id; :}
| KW_SECOND:id
{: RESULT = id; :}
;
// Identifier that contain keyword

View File

@ -120,75 +120,108 @@ public class TimestampArithmeticExpr extends Expr {
@Override
public void analyzeImpl(Analyzer analyzer) throws AnalysisException {
// Check if name of function call is date_sub or date_add.
if (funcName != null) {
if (funcName.toUpperCase().equals("DATE_ADD")
|| funcName.toUpperCase().equals("DAYS_ADD")
|| funcName.toUpperCase().equals("ADDDATE")) {
op = ArithmeticExpr.Operator.ADD;
} else if (funcName.toUpperCase().equals("DATE_SUB")
|| funcName.toUpperCase().equals("DAYS_SUB")
|| funcName.toUpperCase().equals("SUBDATE")) {
op = ArithmeticExpr.Operator.SUBTRACT;
} else {
throw new AnalysisException("Encountered function name '" + funcName
+ "' in timestamp arithmetic expression '" + toSql() + "'. "
+ "Expected function name 'DATE_ADD/DAYS_ADD/ADDDATE'"
+ "or 'DATE_SUB/DAYS_SUB/SUBDATE");
String funcOpName;
if (funcName != null && funcName.equalsIgnoreCase("TIMESTAMPDIFF")) {
timeUnit = TIME_UNITS_MAP.get(timeUnitIdent.toUpperCase());
if (timeUnit == null) {
throw new AnalysisException("Invalid time unit '" + timeUnitIdent
+ "' in timestamp arithmetic expression '" + toSql() + "'.");
}
}
timeUnit = TIME_UNITS_MAP.get(timeUnitIdent.toUpperCase());
if (timeUnit == null) {
throw new AnalysisException("Invalid time unit '" + timeUnitIdent
+ "' in timestamp arithmetic expression '" + toSql() + "'.");
}
Type dateType = fixType();
if (dateType.isDate() && timeUnit.isDateTime()) {
dateType = Type.DATETIME;
}
// The first child must return a timestamp or null.
if (!getChild(0).getType().isDateType() && !getChild(0).getType().isNull()) {
if (!dateType.isValid()) {
throw new AnalysisException("Operand '" + getChild(0).toSql()
+ "' of timestamp arithmetic expression '" + toSql() + "' returns type '"
+ getChild(0).getType() + "'. Expected type 'TIMESTAMP/DATE/DATETIME'.");
Type dateType = fixType();
if (dateType.isDate() && timeUnit.isDateTime()) {
dateType = Type.DATETIME;
}
castChild(dateType, 0);
}
if (!getChild(1).getType().isScalarType()) {
throw new AnalysisException("must be a scalar type.");
}
// The second child must be of type 'INT' or castable to it.
if (!getChild(1).getType().isScalarType(PrimitiveType.INT)) {
if (!ScalarType.canCastTo((ScalarType) getChild(1).getType(), Type.INT)) {
throw new AnalysisException("Operand '" + getChild(1).toSql()
+ "' of timestamp arithmetic expression '" + toSql() + "' returns type '"
+ getChild(1).getType() + "' which is incompatible with expected type 'INT'.");
// The first child must return a timestamp or null.
if (!getChild(0).getType().isDateType() && !getChild(0).getType().isNull()) {
if (!dateType.isValid()) {
throw new AnalysisException("Operand '" + getChild(0).toSql()
+ "' of timestamp arithmetic expression '" + toSql() + "' returns type '"
+ getChild(0).getType() + "'. Expected type 'TIMESTAMP/DATE/DATETIME'.");
}
castChild(dateType, 0);
}
castChild(Type.INT, 1);
}
type = dateType;
opcode = getOpCode();
String funcOpName = String.format("%sS_%s", timeUnit,
(op == ArithmeticExpr.Operator.ADD) ? "ADD" : "SUB");
// For the month interval, use the invisible special-case implementation.
// "ADD_MONTHS(t, m)" by definition is different from "t + INTERVAL m MONTHS".
// if (timeUnit == TimeUnit.MONTH) {
// funcOpName += "_INTERVAL";
// }
// The first child must return a timestamp or null.
if (!getChild(1).getType().isDateType() && !getChild(1).getType().isNull()) {
if (!dateType.isValid()) {
throw new AnalysisException("Operand '" + getChild(1).toSql()
+ "' of timestamp arithmetic expression '" + toSql() + "' returns type '"
+ getChild(1).getType() + "'. Expected type 'TIMESTAMP/DATE/DATETIME'.");
}
castChild(dateType, 1);
}
type = Type.BIGINT;
opcode = getOpCode();
funcOpName = String.format("%sS_%s", timeUnit, "DIFF");
} else {
if (funcName != null) {
if (funcName.toUpperCase().equals("DATE_ADD")
|| funcName.toUpperCase().equals("DAYS_ADD")
|| funcName.toUpperCase().equals("ADDDATE")
|| funcName.toUpperCase().equals("TIMESTAMPADD")) {
op = ArithmeticExpr.Operator.ADD;
} else if (funcName.toUpperCase().equals("DATE_SUB")
|| funcName.toUpperCase().equals("DAYS_SUB")
|| funcName.toUpperCase().equals("SUBDATE")) {
op = ArithmeticExpr.Operator.SUBTRACT;
} else {
throw new AnalysisException("Encountered function name '" + funcName
+ "' in timestamp arithmetic expression '" + toSql() + "'. "
+ "Expected function name 'DATE_ADD/DAYS_ADD/ADDDATE/TIMESTAMPADD'"
+ "or 'DATE_SUB/DAYS_SUB/SUBDATE");
}
}
timeUnit = TIME_UNITS_MAP.get(timeUnitIdent.toUpperCase());
if (timeUnit == null) {
throw new AnalysisException("Invalid time unit '" + timeUnitIdent
+ "' in timestamp arithmetic expression '" + toSql() + "'.");
}
Type dateType = fixType();
if (dateType.isDate() && timeUnit.isDateTime()) {
dateType = Type.DATETIME;
}
// The first child must return a timestamp or null.
if (!getChild(0).getType().isDateType() && !getChild(0).getType().isNull()) {
if (!dateType.isValid()) {
throw new AnalysisException("Operand '" + getChild(0).toSql()
+ "' of timestamp arithmetic expression '" + toSql() + "' returns type '"
+ getChild(0).getType() + "'. Expected type 'TIMESTAMP/DATE/DATETIME'.");
}
castChild(dateType, 0);
}
if (!getChild(1).getType().isScalarType()) {
throw new AnalysisException("must be a scalar type.");
}
// The second child must be of type 'INT' or castable to it.
if (!getChild(1).getType().isScalarType(PrimitiveType.INT)) {
if (!ScalarType.canCastTo((ScalarType) getChild(1).getType(), Type.INT)) {
throw new AnalysisException("Operand '" + getChild(1).toSql()
+ "' of timestamp arithmetic expression '" + toSql() + "' returns type '"
+ getChild(1).getType() + "' which is incompatible with expected type 'INT'.");
}
castChild(Type.INT, 1);
}
type = dateType;
opcode = getOpCode();
funcOpName = String.format("%sS_%s", timeUnit,
(op == ArithmeticExpr.Operator.ADD) ? "ADD" : "SUB");
}
fn = getBuiltinFunction(analyzer, funcOpName.toLowerCase(),
collectChildReturnTypes(), Function.CompareMode.IS_NONSTRICT_SUPERTYPE_OF);
LOG.info("fn is {} name is {}", fn, funcOpName);
LOG.debug("fn is {} name is {}", fn, funcOpName);
}
@Override
protected void toThrift(TExprNode msg) {
msg.node_type = TExprNodeType.COMPUTE_FUNCTION_CALL;
msg.setOpcode(opcode);
msg.setOpcode(opcode);
}
public ArithmeticExpr.Operator getOp() {
@ -258,6 +291,13 @@ public class TimestampArithmeticExpr extends Expr {
public String toSqlImpl() {
StringBuilder strBuilder = new StringBuilder();
if (funcName != null) {
if (funcName.equalsIgnoreCase("TIMESTAMPDIFF") || funcName.equalsIgnoreCase("TIMESTAMPADD")) {
strBuilder.append(funcName).append("(");
strBuilder.append(timeUnitIdent).append(", ");
strBuilder.append(getChild(1).toSql()).append(", ");
strBuilder.append(getChild(0).toSql()).append(")");
return strBuilder.toString();
}
// Function-call like version.
strBuilder.append(funcName).append("(");
strBuilder.append(getChild(0).toSql()).append(", ");

View File

@ -107,7 +107,7 @@ import org.apache.doris.qe.SqlModeHelper;
keywordMap.put("bigint", new Integer(SqlParserSymbols.KW_BIGINT));
keywordMap.put("bitmap", new Integer(SqlParserSymbols.KW_BITMAP));
keywordMap.put("boolean", new Integer(SqlParserSymbols.KW_BOOLEAN));
keywordMap.put("hll", new Integer(SqlParserSymbols.KW_HLL));
keywordMap.put("day", new Integer(SqlParserSymbols.KW_DAY));
keywordMap.put("both", new Integer(SqlParserSymbols.KW_BOTH));
keywordMap.put("broker", new Integer(SqlParserSymbols.KW_BROKER));
keywordMap.put("by", new Integer(SqlParserSymbols.KW_BY));
@ -199,8 +199,10 @@ import org.apache.doris.qe.SqlModeHelper;
keywordMap.put("hash", new Integer(SqlParserSymbols.KW_HASH));
keywordMap.put("having", new Integer(SqlParserSymbols.KW_HAVING));
keywordMap.put("help", new Integer(SqlParserSymbols.KW_HELP));
keywordMap.put("hll", new Integer(SqlParserSymbols.KW_HLL));
keywordMap.put("hll_union", new Integer(SqlParserSymbols.KW_HLL_UNION));
keywordMap.put("bitmap_union", new Integer(SqlParserSymbols.KW_BITMAP_UNION));
keywordMap.put("hour", new Integer(SqlParserSymbols.KW_HOUR));
keywordMap.put("hub", new Integer(SqlParserSymbols.KW_HUB));
keywordMap.put("identified", new Integer(SqlParserSymbols.KW_IDENTIFIED));
keywordMap.put("if", new Integer(SqlParserSymbols.KW_IF));
@ -241,7 +243,9 @@ import org.apache.doris.qe.SqlModeHelper;
keywordMap.put("maxvalue", new Integer(SqlParserSymbols.KW_MAX_VALUE));
keywordMap.put("merge", new Integer(SqlParserSymbols.KW_MERGE));
keywordMap.put("min", new Integer(SqlParserSymbols.KW_MIN));
keywordMap.put("minute", new Integer(SqlParserSymbols.KW_MINUTE));
keywordMap.put("modify", new Integer(SqlParserSymbols.KW_MODIFY));
keywordMap.put("month", new Integer(SqlParserSymbols.KW_MONTH));
keywordMap.put("name", new Integer(SqlParserSymbols.KW_NAME));
keywordMap.put("names", new Integer(SqlParserSymbols.KW_NAMES));
keywordMap.put("negative", new Integer(SqlParserSymbols.KW_NEGATIVE));
@ -301,6 +305,7 @@ import org.apache.doris.qe.SqlModeHelper;
keywordMap.put("row", new Integer(SqlParserSymbols.KW_ROW));
keywordMap.put("rows", new Integer(SqlParserSymbols.KW_ROWS));
keywordMap.put("schemas", new Integer(SqlParserSymbols.KW_SCHEMAS));
keywordMap.put("second", new Integer(SqlParserSymbols.KW_SECOND));
keywordMap.put("select", new Integer(SqlParserSymbols.KW_SELECT));
keywordMap.put("semi", new Integer(SqlParserSymbols.KW_SEMI));
keywordMap.put("serializable", new Integer(SqlParserSymbols.KW_SERIALIZABLE));
@ -349,12 +354,14 @@ import org.apache.doris.qe.SqlModeHelper;
keywordMap.put("view", new Integer(SqlParserSymbols.KW_VIEW));
keywordMap.put("materialized", new Integer(SqlParserSymbols.KW_MATERIALIZED));
keywordMap.put("warnings", new Integer(SqlParserSymbols.KW_WARNINGS));
keywordMap.put("week", new Integer(SqlParserSymbols.KW_WEEK));
keywordMap.put("whitelist", new Integer(SqlParserSymbols.KW_WHITELIST));
keywordMap.put("when", new Integer(SqlParserSymbols.KW_WHEN));
keywordMap.put("where", new Integer(SqlParserSymbols.KW_WHERE));
keywordMap.put("with", new Integer(SqlParserSymbols.KW_WITH));
keywordMap.put("work", new Integer(SqlParserSymbols.KW_WORK));
keywordMap.put("write", new Integer(SqlParserSymbols.KW_WRITE));
keywordMap.put("year", new Integer(SqlParserSymbols.KW_YEAR));
keywordMap.put("||", new Integer(SqlParserSymbols.KW_PIPE));
}

View File

@ -226,6 +226,21 @@ visible_functions = [
[['convert_tz'], 'DATETIME', ['DATETIME', 'VARCHAR', 'VARCHAR'],
'_ZN5doris18TimestampFunctions10convert_tzEPN9doris_udf15FunctionContextERKNS1_11DateTimeValERKNS1_9StringValES9_'],
[['years_diff'], 'BIGINT', ['DATETIME', 'DATETIME'],
'_ZN5doris18TimestampFunctions10years_diffEPN9doris_udf15FunctionContextERKNS1_11DateTimeValES6_'],
[['months_diff'], 'BIGINT', ['DATETIME', 'DATETIME'],
'_ZN5doris18TimestampFunctions11months_diffEPN9doris_udf15FunctionContextERKNS1_11DateTimeValES6_'],
[['weeks_diff'], 'BIGINT', ['DATETIME', 'DATETIME'],
'_ZN5doris18TimestampFunctions10weeks_diffEPN9doris_udf15FunctionContextERKNS1_11DateTimeValES6_'],
[['days_diff'], 'BIGINT', ['DATETIME', 'DATETIME'],
'_ZN5doris18TimestampFunctions9days_diffEPN9doris_udf15FunctionContextERKNS1_11DateTimeValES6_'],
[['hours_diff'], 'BIGINT', ['DATETIME', 'DATETIME'],
'_ZN5doris18TimestampFunctions10hours_diffEPN9doris_udf15FunctionContextERKNS1_11DateTimeValES6_'],
[['minutes_diff'], 'BIGINT', ['DATETIME', 'DATETIME'],
'_ZN5doris18TimestampFunctions12minutes_diffEPN9doris_udf15FunctionContextERKNS1_11DateTimeValES6_'],
[['seconds_diff'], 'BIGINT', ['DATETIME', 'DATETIME'],
'_ZN5doris18TimestampFunctions12seconds_diffEPN9doris_udf15FunctionContextERKNS1_11DateTimeValES6_'],
# Math builtin functions
[['pi'], 'DOUBLE', [],
'_ZN5doris13MathFunctions2piEPN9doris_udf15FunctionContextE'],