You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@doris.apache.org by yi...@apache.org on 2023/01/31 02:08:51 UTC

[doris] branch master updated: [Bug](date) Fix invalid date (#16205)

This is an automated email from the ASF dual-hosted git repository.

yiguolei pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new 471db80f69 [Bug](date) Fix invalid date (#16205)
471db80f69 is described below

commit 471db80f69826498fe279fe6ff3885eb8aaa6ee1
Author: Gabriel <ga...@gmail.com>
AuthorDate: Tue Jan 31 10:08:44 2023 +0800

    [Bug](date) Fix invalid date (#16205)
    
    Issue Number: close #15777
---
 be/src/vec/exprs/vliteral.cpp                      | 28 ++++++++++------
 .../org/apache/doris/analysis/DateLiteral.java     | 18 +++++++++--
 .../apache/doris/analysis/ExpressionFunctions.java | 13 +++++++-
 .../org/apache/doris/analysis/StringLiteral.java   |  5 +++
 .../data/datatype_p0/date/test_invalid_date.out    |  7 ++++
 .../datatype_p0/date/test_invalid_date.groovy      | 37 ++++++++++++++++++++++
 6 files changed, 95 insertions(+), 13 deletions(-)

diff --git a/be/src/vec/exprs/vliteral.cpp b/be/src/vec/exprs/vliteral.cpp
index a0ef2deb17..782c8161b2 100644
--- a/be/src/vec/exprs/vliteral.cpp
+++ b/be/src/vec/exprs/vliteral.cpp
@@ -93,28 +93,36 @@ void VLiteral::init(const TExprNode& node) {
         }
         case TYPE_DATE: {
             VecDateTimeValue value;
-            value.from_date_str(node.date_literal.value.c_str(), node.date_literal.value.size());
-            value.cast_to_date();
-            field = Int64(*reinterpret_cast<__int64_t*>(&value));
+            if (value.from_date_str(node.date_literal.value.c_str(),
+                                    node.date_literal.value.size())) {
+                value.cast_to_date();
+                field = Int64(*reinterpret_cast<__int64_t*>(&value));
+            }
             break;
         }
         case TYPE_DATEV2: {
             DateV2Value<DateV2ValueType> value;
-            value.from_date_str(node.date_literal.value.c_str(), node.date_literal.value.size());
-            field = value.to_date_int_val();
+            if (value.from_date_str(node.date_literal.value.c_str(),
+                                    node.date_literal.value.size())) {
+                field = value.to_date_int_val();
+            }
             break;
         }
         case TYPE_DATETIMEV2: {
             DateV2Value<DateTimeV2ValueType> value;
-            value.from_date_str(node.date_literal.value.c_str(), node.date_literal.value.size());
-            field = value.to_date_int_val();
+            if (value.from_date_str(node.date_literal.value.c_str(),
+                                    node.date_literal.value.size())) {
+                field = value.to_date_int_val();
+            }
             break;
         }
         case TYPE_DATETIME: {
             VecDateTimeValue value;
-            value.from_date_str(node.date_literal.value.c_str(), node.date_literal.value.size());
-            value.to_datetime();
-            field = Int64(*reinterpret_cast<__int64_t*>(&value));
+            if (value.from_date_str(node.date_literal.value.c_str(),
+                                    node.date_literal.value.size())) {
+                value.to_datetime();
+                field = Int64(*reinterpret_cast<__int64_t*>(&value));
+            }
             break;
         }
         case TYPE_STRING:
diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/DateLiteral.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/DateLiteral.java
index 203b0d0696..a286862a23 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/analysis/DateLiteral.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/DateLiteral.java
@@ -627,6 +627,13 @@ public class DateLiteral extends LiteralExpr {
         }
         msg.node_type = TExprNodeType.DATE_LITERAL;
         msg.date_literal = new TDateLiteral(getStringValue());
+        try {
+            checkValueValid();
+        } catch (AnalysisException e) {
+            // If date value is invalid, set this to null
+            msg.node_type = TExprNodeType.NULL_LITERAL;
+            msg.setIsNullable(true);
+        }
     }
 
     @Override
@@ -775,6 +782,11 @@ public class DateLiteral extends LiteralExpr {
         }
     }
 
+    private boolean isLeapYear() {
+        return ((year % 4) == 0) && ((year % 100 != 0) || ((year % 400) == 0 && year > 0));
+    }
+
+    // Validation check should be same as DateV2Value<T>::is_invalid in BE
     @Override
     public void checkValueValid() throws AnalysisException {
         if (year < 0 || year > 9999) {
@@ -783,8 +795,10 @@ public class DateLiteral extends LiteralExpr {
         if (month < 1 || month > 12) {
             throw new AnalysisException("DateLiteral has invalid month value: " + month);
         }
-        if (day < 1 || day > 31) {
-            throw new AnalysisException("DateLiteral has invalid day value: " + day);
+        if (day < 1 || day > DAYS_IN_MONTH[(int) month]) {
+            if (!(month == 2 && day == 29 && isLeapYear())) {
+                throw new AnalysisException("DateLiteral has invalid day value: " + day);
+            }
         }
         if (type.isDatetimeV2() || type.isDatetime()) {
             if (hour < 0 || hour > 24) {
diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/ExpressionFunctions.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/ExpressionFunctions.java
index 02c7b26b25..e7dae9617b 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/analysis/ExpressionFunctions.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/ExpressionFunctions.java
@@ -98,7 +98,18 @@ public enum ExpressionFunctions {
             FEFunctionInvoker invoker = getFunction(signature);
             if (invoker != null) {
                 try {
-                    return invoker.invoke(constExpr.getChildrenWithoutCast());
+                    if (fn.getReturnType().isDateType()) {
+                        Expr dateLiteral = invoker.invoke(constExpr.getChildrenWithoutCast());
+                        Preconditions.checkArgument(dateLiteral instanceof DateLiteral);
+                        try {
+                            ((DateLiteral) dateLiteral).checkValueValid();
+                        } catch (AnalysisException e) {
+                            return NullLiteral.create(dateLiteral.getType());
+                        }
+                        return dateLiteral;
+                    } else {
+                        return invoker.invoke(constExpr.getChildrenWithoutCast());
+                    }
                 } catch (AnalysisException e) {
                     LOG.debug("failed to invoke", e);
                     return constExpr;
diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/StringLiteral.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/StringLiteral.java
index 37ab650fb7..59c34c4a7b 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/analysis/StringLiteral.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/StringLiteral.java
@@ -194,6 +194,11 @@ public class StringLiteral extends LiteralExpr {
                 throw e;
             }
         }
+        try {
+            newLiteral.checkValueValid();
+        } catch (AnalysisException e) {
+            return NullLiteral.create(newLiteral.getType());
+        }
         return newLiteral;
     }
 
diff --git a/regression-test/data/datatype_p0/date/test_invalid_date.out b/regression-test/data/datatype_p0/date/test_invalid_date.out
new file mode 100644
index 0000000000..80b3c3963d
--- /dev/null
+++ b/regression-test/data/datatype_p0/date/test_invalid_date.out
@@ -0,0 +1,7 @@
+-- This file is automatically generated. You should know what you did if you want to edit this
+-- !sql1 --
+\N
+
+-- !sql2 --
+\N
+
diff --git a/regression-test/suites/datatype_p0/date/test_invalid_date.groovy b/regression-test/suites/datatype_p0/date/test_invalid_date.groovy
new file mode 100644
index 0000000000..6b683d90b6
--- /dev/null
+++ b/regression-test/suites/datatype_p0/date/test_invalid_date.groovy
@@ -0,0 +1,37 @@
+
+// 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.
+
+suite("test_invalid_date") {
+    def tbName = "test_invalid_date"
+    sql "DROP TABLE IF EXISTS ${tbName}"
+    sql """
+            CREATE TABLE IF NOT EXISTS ${tbName} (
+                c0 int,
+                c1 char(10),
+                c2 date,
+                c3 datev2
+            )
+            UNIQUE KEY(c0)
+            DISTRIBUTED BY HASH(c0) BUCKETS 5 properties("replication_num" = "1");
+        """
+    sql "insert into ${tbName} values(1, 'test1', '2000-01-01', '2000-01-01')"
+
+    qt_sql1 "select str_to_date('202301', '%Y%m');"
+    qt_sql2 "select str_to_date('202301', '%Y%m') from ${tbName}"
+    sql "DROP TABLE ${tbName}"
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@doris.apache.org
For additional commands, e-mail: commits-help@doris.apache.org