Skip to content

Commit

Permalink
[Feature](function) Support function quarters_add/sub for nereids (#4…
Browse files Browse the repository at this point in the history
…5370)

### What problem does this PR solve?

Issue Number: close #xxx

Related PR: #xxx

Problem Summary:

1. BE already has its implementation. now add nereids function
signatures.

```sql
mysql> select quarters_add("2020-12-12", 1);
+-----------------------------------------------+
| quarters_add(cast('2020-12-12' as DATEV2), 1) |
+-----------------------------------------------+
| 2021-03-12                                    |
+-----------------------------------------------+
1 row in set (0.10 sec)

mysql> select date_sub("2020-12-12", interval 10 quarter);
+------------------------------------------------+
| quarters_sub(cast('2020-12-12' as DATEV2), 10) |
+------------------------------------------------+
| 2018-06-12                                     |
+------------------------------------------------+
1 row in set (0.11 sec)
```

2. for date operations' template implementations in BE, we choose
years_add to cover its standard testcases to test the base template.
  • Loading branch information
zclllyybb authored Dec 26, 2024
1 parent a1439fd commit d5e967c
Show file tree
Hide file tree
Showing 14 changed files with 1,228 additions and 10 deletions.
6 changes: 4 additions & 2 deletions be/src/vec/functions/function_date_or_datetime_computation.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,9 @@ struct AddQuartersImpl {
return date_time_add<TimeUnit::MONTH, ArgType, ReturnType>(t, 3 * delta, is_null);
}

static DataTypes get_variadic_argument_types() { return {std::make_shared<ArgType>()}; }
static DataTypes get_variadic_argument_types() {
return {std::make_shared<ArgType>(), std::make_shared<DataTypeInt32>()};
}
};

template <typename Transform, typename DateType>
Expand All @@ -156,7 +158,7 @@ struct SubtractIntervalImpl {
}

static DataTypes get_variadic_argument_types() {
return {std::make_shared<DateType>(), std::make_shared<DataTypeInt32>()};
return Transform::get_variadic_argument_types();
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,7 @@ QUANTILE_UNION: 'QUANTILE_UNION';
QUERY: 'QUERY';
QUOTA: 'QUOTA';
QUALIFY: 'QUALIFY';
QUARTER: 'QUARTER';
RANDOM: 'RANDOM';
RANGE: 'RANGE';
READ: 'READ';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1508,9 +1508,7 @@ valueExpression
;

datetimeUnit
: YEAR | MONTH
| WEEK | DAY
| HOUR | MINUTE | SECOND
:YEAR | MONTH | QUARTER | WEEK | DAY | HOUR | MINUTE | SECOND
;

primaryExpression
Expand Down Expand Up @@ -1704,7 +1702,7 @@ interval
;

unitIdentifier
: YEAR | MONTH | WEEK | DAY | HOUR | MINUTE | SECOND
: YEAR | QUARTER | MONTH | WEEK | DAY | HOUR | MINUTE | SECOND
;

dataTypeWithNullable
Expand Down Expand Up @@ -2057,7 +2055,8 @@ nonReserved
| PROPERTIES
| PROPERTY
| QUANTILE_STATE
| QUANTILE_UNION
| QUANTILE_UNION
| QUARTER
| QUERY
| QUOTA
| QUALIFY
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,8 @@
import org.apache.doris.nereids.trees.expressions.functions.scalar.QuantilePercent;
import org.apache.doris.nereids.trees.expressions.functions.scalar.QuantileStateEmpty;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Quarter;
import org.apache.doris.nereids.trees.expressions.functions.scalar.QuartersAdd;
import org.apache.doris.nereids.trees.expressions.functions.scalar.QuartersSub;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Quote;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Radians;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Random;
Expand Down Expand Up @@ -831,6 +833,8 @@ public class BuiltinScalarFunctions implements FunctionHelper {
scalar(QuantilePercent.class, "quantile_percent"),
scalar(QuantileStateEmpty.class, "quantile_state_empty"),
scalar(Quarter.class, "quarter"),
scalar(QuartersAdd.class, "quarters_add"),
scalar(QuartersSub.class, "quarters_sub"),
scalar(Radians.class, "radians"),
scalar(Random.class, "rand", "random"),
scalar(Regexp.class, "regexp"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,8 @@
import org.apache.doris.nereids.trees.expressions.functions.scalar.MonthsDiff;
import org.apache.doris.nereids.trees.expressions.functions.scalar.MonthsSub;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Now;
import org.apache.doris.nereids.trees.expressions.functions.scalar.QuartersAdd;
import org.apache.doris.nereids.trees.expressions.functions.scalar.QuartersSub;
import org.apache.doris.nereids.trees.expressions.functions.scalar.SecondCeil;
import org.apache.doris.nereids.trees.expressions.functions.scalar.SecondFloor;
import org.apache.doris.nereids.trees.expressions.functions.scalar.SecondsAdd;
Expand Down Expand Up @@ -2367,6 +2369,7 @@ public Expression visitTimestampdiff(TimestampdiffContext ctx) {
Expression start = (Expression) visit(ctx.startTimestamp);
Expression end = (Expression) visit(ctx.endTimestamp);
String unit = ctx.unit.getText();
// TODO: support quarters_diff
if ("YEAR".equalsIgnoreCase(unit)) {
return new YearsDiff(end, start);
} else if ("MONTH".equalsIgnoreCase(unit)) {
Expand Down Expand Up @@ -2394,6 +2397,8 @@ public Expression visitTimestampadd(TimestampaddContext ctx) {
String unit = ctx.unit.getText();
if ("YEAR".equalsIgnoreCase(unit)) {
return new YearsAdd(end, start);
} else if ("QUARTER".equalsIgnoreCase(unit)) {
return new QuartersAdd(end, start);
} else if ("MONTH".equalsIgnoreCase(unit)) {
return new MonthsAdd(end, start);
} else if ("WEEK".equalsIgnoreCase(unit)) {
Expand All @@ -2409,7 +2414,6 @@ public Expression visitTimestampadd(TimestampaddContext ctx) {
}
throw new ParseException("Unsupported time stamp add time unit: " + unit
+ ", supported time unit: YEAR/MONTH/WEEK/DAY/HOUR/MINUTE/SECOND", ctx);

}

@Override
Expand All @@ -2423,6 +2427,8 @@ public Expression visitDate_add(Date_addContext ctx) {

if ("Year".equalsIgnoreCase(ctx.unit.getText())) {
return new YearsAdd(timeStamp, amount);
} else if ("QUARTER".equalsIgnoreCase(ctx.unit.getText())) {
return new QuartersAdd(timeStamp, amount);
} else if ("MONTH".equalsIgnoreCase(ctx.unit.getText())) {
return new MonthsAdd(timeStamp, amount);
} else if ("WEEK".equalsIgnoreCase(ctx.unit.getText())) {
Expand Down Expand Up @@ -2485,6 +2491,8 @@ public Expression visitDate_sub(Date_subContext ctx) {

if ("Year".equalsIgnoreCase(ctx.unit.getText())) {
return new YearsSub(timeStamp, amount);
} else if ("QUARTER".equalsIgnoreCase(ctx.unit.getText())) {
return new QuartersSub(timeStamp, amount);
} else if ("MONTH".equalsIgnoreCase(ctx.unit.getText())) {
return new MonthsSub(timeStamp, amount);
} else if ("WEEK".equalsIgnoreCase(ctx.unit.getText())) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@
import java.time.temporal.ChronoUnit;

/**
* executable function:
* date_add/sub, years/months/week/days/hours/minutes/seconds_add/sub, datediff
* executable function: date_add/sub, years/quarters/months/week/days/hours/minutes/seconds_add/sub, datediff
*/
public class DateTimeArithmetic {
/**
Expand Down Expand Up @@ -102,6 +101,29 @@ public static Expression yearsAdd(DateTimeV2Literal date, IntegerLiteral year) {
return date.plusYears(year.getValue());
}

/**
* datetime arithmetic function quarters-add.
*/
@ExecFunction(name = "quarters_add")
public static Expression quartersAdd(DateLiteral date, IntegerLiteral quarter) {
return date.plusMonths(3 * quarter.getValue());
}

@ExecFunction(name = "quarters_add")
public static Expression quartersAdd(DateTimeLiteral date, IntegerLiteral quarter) {
return date.plusMonths(3 * quarter.getValue());
}

@ExecFunction(name = "quarters_add")
public static Expression quartersAdd(DateV2Literal date, IntegerLiteral quarter) {
return date.plusMonths(3 * quarter.getValue());
}

@ExecFunction(name = "quarters_add")
public static Expression quartersAdd(DateTimeV2Literal date, IntegerLiteral quarter) {
return date.plusMonths(3 * quarter.getValue());
}

/**
* datetime arithmetic function months-add.
*/
Expand Down Expand Up @@ -295,6 +317,29 @@ public static Expression yearsSub(DateTimeV2Literal date, IntegerLiteral year) {
return yearsAdd(date, new IntegerLiteral(-year.getValue()));
}

/**
* datetime arithmetic function quarters-sub.
*/
@ExecFunction(name = "quarters_sub")
public static Expression quartersSub(DateLiteral date, IntegerLiteral quarter) {
return quartersAdd(date, new IntegerLiteral(-quarter.getValue()));
}

@ExecFunction(name = "quarters_sub")
public static Expression quartersSub(DateTimeLiteral date, IntegerLiteral quarter) {
return quartersAdd(date, new IntegerLiteral(-quarter.getValue()));
}

@ExecFunction(name = "quarters_sub")
public static Expression quartersSub(DateV2Literal date, IntegerLiteral quarter) {
return quartersAdd(date, new IntegerLiteral(-quarter.getValue()));
}

@ExecFunction(name = "quarters_sub")
public static Expression quartersSub(DateTimeV2Literal date, IntegerLiteral quarter) {
return quartersAdd(date, new IntegerLiteral(-quarter.getValue()));
}

/**
* datetime arithmetic function months-sub
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// 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.

package org.apache.doris.nereids.trees.expressions.functions.scalar;

import org.apache.doris.catalog.FunctionSignature;
import org.apache.doris.common.Config;
import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.expressions.functions.ComputeSignatureForDateArithmetic;
import org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature;
import org.apache.doris.nereids.trees.expressions.functions.PropagateNullableOnDateLikeV2Args;
import org.apache.doris.nereids.trees.expressions.shape.BinaryExpression;
import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
import org.apache.doris.nereids.types.DateTimeType;
import org.apache.doris.nereids.types.DateTimeV2Type;
import org.apache.doris.nereids.types.DateType;
import org.apache.doris.nereids.types.DateV2Type;
import org.apache.doris.nereids.types.IntegerType;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;

import java.util.List;

/**
* ScalarFunction 'quarters_add'.
*/
public class QuartersAdd extends ScalarFunction implements BinaryExpression, ExplicitlyCastableSignature,
ComputeSignatureForDateArithmetic, PropagateNullableOnDateLikeV2Args {

// When enable_date_conversion is true, we prefer to V2 signature.
// This preference follows original planner. refer to ScalarType.getDefaultDateType()
private static final List<FunctionSignature> SIGNATURES = Config.enable_date_conversion
? ImmutableList.of(
FunctionSignature.ret(DateTimeV2Type.SYSTEM_DEFAULT).args(DateTimeV2Type.SYSTEM_DEFAULT,
IntegerType.INSTANCE),
FunctionSignature.ret(DateV2Type.INSTANCE).args(DateV2Type.INSTANCE, IntegerType.INSTANCE),
FunctionSignature.ret(DateTimeType.INSTANCE).args(DateTimeType.INSTANCE, IntegerType.INSTANCE),
FunctionSignature.ret(DateType.INSTANCE).args(DateType.INSTANCE, IntegerType.INSTANCE))
: ImmutableList.of(
FunctionSignature.ret(DateTimeType.INSTANCE).args(DateTimeType.INSTANCE, IntegerType.INSTANCE),
FunctionSignature.ret(DateType.INSTANCE).args(DateType.INSTANCE, IntegerType.INSTANCE),
FunctionSignature.ret(DateTimeV2Type.SYSTEM_DEFAULT).args(DateTimeV2Type.SYSTEM_DEFAULT,
IntegerType.INSTANCE),
FunctionSignature.ret(DateV2Type.INSTANCE).args(DateV2Type.INSTANCE, IntegerType.INSTANCE));

public QuartersAdd(Expression arg0, Expression arg1) {
super("quarters_add", arg0, arg1);
}

@Override
public QuartersAdd withChildren(List<Expression> children) {
Preconditions.checkArgument(children.size() == 2);
return new QuartersAdd(children.get(0), children.get(1));
}

@Override
public List<FunctionSignature> getSignatures() {
return SIGNATURES;
}

@Override
public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
return visitor.visitQuartersAdd(this, context);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// 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.

package org.apache.doris.nereids.trees.expressions.functions.scalar;

import org.apache.doris.catalog.FunctionSignature;
import org.apache.doris.common.Config;
import org.apache.doris.nereids.trees.expressions.Expression;
import org.apache.doris.nereids.trees.expressions.functions.ComputeSignatureForDateArithmetic;
import org.apache.doris.nereids.trees.expressions.functions.ExplicitlyCastableSignature;
import org.apache.doris.nereids.trees.expressions.functions.PropagateNullableOnDateLikeV2Args;
import org.apache.doris.nereids.trees.expressions.shape.BinaryExpression;
import org.apache.doris.nereids.trees.expressions.visitor.ExpressionVisitor;
import org.apache.doris.nereids.types.DateTimeType;
import org.apache.doris.nereids.types.DateTimeV2Type;
import org.apache.doris.nereids.types.DateType;
import org.apache.doris.nereids.types.DateV2Type;
import org.apache.doris.nereids.types.IntegerType;

import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;

import java.util.List;

/**
* ScalarFunction 'quarters_sub'.
*/
public class QuartersSub extends ScalarFunction implements BinaryExpression, ExplicitlyCastableSignature,
ComputeSignatureForDateArithmetic, PropagateNullableOnDateLikeV2Args {

// When enable_date_conversion is true, we prefer to V2 signature.
// This preference follows original planner. refer to ScalarType.getDefaultDateType()
private static final List<FunctionSignature> SIGNATURES = Config.enable_date_conversion
? ImmutableList.of(
FunctionSignature.ret(DateTimeV2Type.SYSTEM_DEFAULT).args(DateTimeV2Type.SYSTEM_DEFAULT,
IntegerType.INSTANCE),
FunctionSignature.ret(DateV2Type.INSTANCE).args(DateV2Type.INSTANCE, IntegerType.INSTANCE),
FunctionSignature.ret(DateTimeType.INSTANCE).args(DateTimeType.INSTANCE, IntegerType.INSTANCE),
FunctionSignature.ret(DateType.INSTANCE).args(DateType.INSTANCE, IntegerType.INSTANCE))
: ImmutableList.of(
FunctionSignature.ret(DateTimeType.INSTANCE).args(DateTimeType.INSTANCE, IntegerType.INSTANCE),
FunctionSignature.ret(DateType.INSTANCE).args(DateType.INSTANCE, IntegerType.INSTANCE),
FunctionSignature.ret(DateTimeV2Type.SYSTEM_DEFAULT).args(DateTimeV2Type.SYSTEM_DEFAULT,
IntegerType.INSTANCE),
FunctionSignature.ret(DateV2Type.INSTANCE).args(DateV2Type.INSTANCE, IntegerType.INSTANCE));

public QuartersSub(Expression arg0, Expression arg1) {
super("quarters_sub", arg0, arg1);
}

@Override
public QuartersSub withChildren(List<Expression> children) {
Preconditions.checkArgument(children.size() == 2);
return new QuartersSub(children.get(0), children.get(1));
}

@Override
public List<FunctionSignature> getSignatures() {
return SIGNATURES;
}

@Override
public <R, C> R accept(ExpressionVisitor<R, C> visitor, C context) {
return visitor.visitQuartersSub(this, context);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,8 @@
import org.apache.doris.nereids.trees.expressions.functions.scalar.QuantilePercent;
import org.apache.doris.nereids.trees.expressions.functions.scalar.QuantileStateEmpty;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Quarter;
import org.apache.doris.nereids.trees.expressions.functions.scalar.QuartersAdd;
import org.apache.doris.nereids.trees.expressions.functions.scalar.QuartersSub;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Quote;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Radians;
import org.apache.doris.nereids.trees.expressions.functions.scalar.Random;
Expand Down Expand Up @@ -1763,6 +1765,14 @@ default R visitQuarter(Quarter quarter, C context) {
return visitScalarFunction(quarter, context);
}

default R visitQuartersAdd(QuartersAdd quartersAdd, C context) {
return visitScalarFunction(quartersAdd, context);
}

default R visitQuartersSub(QuartersSub quartersSub, C context) {
return visitScalarFunction(quartersSub, context);
}

default R visitRadians(Radians radians, C context) {
return visitScalarFunction(radians, context);
}
Expand Down
Loading

0 comments on commit d5e967c

Please sign in to comment.