kangkaisen commented on a change in pull request #2725: Add
timestampadd/timestampdiff function
URL: https://github.com/apache/incubator-doris/pull/2725#discussion_r365064527
##########
File path:
fe/src/main/java/org/apache/doris/analysis/TimestampArithmeticExpr.java
##########
@@ -120,65 +120,142 @@ private Type fixType() {
@Override
public void analyzeImpl(Analyzer analyzer) throws AnalysisException {
// Check if name of function call is date_sub or date_add.
+ String funcOpName;
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;
+ if (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() + "'.");
+ }
+ 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);
+ }
+
+ // 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 {
- 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");
+ 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");
+ // For the month interval, use the invisible special-case
implementation.
Review comment:
remove this comment?
----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
For queries about this service, please contact Infrastructure at:
[email protected]
With regards,
Apache Git Services
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]