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

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


The following commit(s) were added to refs/heads/master by this push:
     new 065b979  [Bug] behavior of function str_to_date() and date_format() on 
BE and FE is inconsistent (#4612)
065b979 is described below

commit 065b979f3503cda3ad4b110b7d44f482a1380815
Author: qiye <jianliang5...@gmail.com>
AuthorDate: Thu Sep 17 10:10:19 2020 +0800

    [Bug] behavior of function str_to_date() and date_format() on BE and FE is 
inconsistent (#4612)
    
    1. add date range check in `DateLiteral` for `FEFunctions`
    2. `select str_to_date(202009,'%Y%m')` and `select str_to_date(str,'%Y%m') 
from tb where tb.str = '202009'` will return same output `2020-09-00`.
    3. add support of zero-date to function `str_to_date()`,`date_format()`
    4. fix FE can calculate negative value bug, eg: `select 
str_to_date('-2020', '%Y')` will return `NULL` instead of date value.
    
    current behavior is same as MySQL **without** sql_mode `NO_ZERO_IN_DATE` 
and `NO_ZERO_DATE`.
    
    **current behavior**
    ```
    mysql> select siteid,str_to_date(siteid,'%Y%m%d') from table2  order by 
siteid;
    +------------+---------------------------------+
    | siteid     | str_to_date(`siteid`, '%Y%m%d') |
    +------------+---------------------------------+
    |          1 | 2001-00-00                      |
    |          2 | 2002-00-00                      |
    |          2 | 2002-00-00                      |
    |          3 | 2003-00-00                      |
    |          4 | 2004-00-00                      |
    |          5 | 2005-00-00                      |
    |         20 | 2020-00-00                      |
    |        202 | 0202-00-00                      |
    |       2020 | 2020-00-00                      |
    |      20209 | 2020-09-00                      |
    |     202008 | 2020-08-00                      |
    |     202009 | 2020-09-00                      |
    |    2020009 | 2020-00-09                      |
    |   20200009 | 2020-00-09                      |
    |   20201309 | NULL                            |
    | 2020090909 | 2020-09-09                      |
    +------------+---------------------------------+
    
    mysql> select 
str_to_date('2','%Y%m%d'),str_to_date('20','%Y%m%d'),str_to_date('202','%Y%m%d'),str_to_date('2020','%Y%m%d'),str_to_date('20209','%Y%m%d'),str_to_date('202009','%Y%m%d'),str_to_date('2020099','%Y%m%d'),str_to_date('20200909','%Y%m%d'),str_to_date('2020090909','%Y%m%d'),str_to_date('2020009','%Y%m%d'),str_to_date('20200009','%Y%m%d'),str_to_date('20201309','%Y%m%d');
    
+----------------------------+-----------------------------+------------------------------+-------------------------------+--------------------------------+---------------------------------+----------------------------------+-----------------------------------+-------------------------------------+----------------------------------+-----------------------------------+-----------------------------------+
    | str_to_date('2', '%Y%m%d') | str_to_date('20', '%Y%m%d') | 
str_to_date('202', '%Y%m%d') | str_to_date('2020', '%Y%m%d') | 
str_to_date('20209', '%Y%m%d') | str_to_date('202009', '%Y%m%d') | 
str_to_date('2020099', '%Y%m%d') | str_to_date('20200909', '%Y%m%d') | 
str_to_date('2020090909', '%Y%m%d') | str_to_date('2020009', '%Y%m%d') | 
str_to_date('20200009', '%Y%m%d') | str_to_date('20201309', '%Y%m%d') |
    
+----------------------------+-----------------------------+------------------------------+-------------------------------+--------------------------------+---------------------------------+----------------------------------+-----------------------------------+-------------------------------------+----------------------------------+-----------------------------------+-----------------------------------+
    | 2002-00-00                 | 2020-00-00                  | 0202-00-00     
              | 2020-00-00                    | 2020-09-00                     
| 2020-09-00                      | 2020-09-09                       | 
2020-09-09                        | 2020-09-09                          | 
2020-00-09                       | 2020-00-09                        | NULL     
                         |
    
+----------------------------+-----------------------------+------------------------------+-------------------------------+--------------------------------+---------------------------------+----------------------------------+-----------------------------------+-------------------------------------+----------------------------------+-----------------------------------+-----------------------------------+
    ```
---
 be/src/runtime/datetime_value.cpp                  |  5 +--
 be/test/runtime/datetime_value_test.cpp            | 10 ++++--
 .../org/apache/doris/analysis/DateLiteral.java     | 26 +++++++++++++-
 .../org/apache/doris/analysis/DateLiteralTest.java | 41 ++++++++++++++++++++++
 4 files changed, 74 insertions(+), 8 deletions(-)

diff --git a/be/src/runtime/datetime_value.cpp 
b/be/src/runtime/datetime_value.cpp
index 67be081..29e4761 100644
--- a/be/src/runtime/datetime_value.cpp
+++ b/be/src/runtime/datetime_value.cpp
@@ -74,10 +74,7 @@ bool DateTimeValue::check_range() const {
 }
 
 bool DateTimeValue::check_date() const {
-    if (_month == 0 || _day == 0) {
-        return true;
-    }
-    if (_day > s_days_in_month[_month]) {
+    if (_month != 0 && _day > s_days_in_month[_month]) {
         // Feb 29 in leap year is valid.
         if (_month == 2 && _day == 29 && is_leap(_year)) {
             return false;
diff --git a/be/test/runtime/datetime_value_test.cpp 
b/be/test/runtime/datetime_value_test.cpp
index 4d49cc9..e69535e 100644
--- a/be/test/runtime/datetime_value_test.cpp
+++ b/be/test/runtime/datetime_value_test.cpp
@@ -236,11 +236,11 @@ TEST_F(DateTimeValueTest, check_date) {
     ASSERT_TRUE(value.from_date_int64(19880201));
 
     value._month = 0;
-    ASSERT_TRUE(value.check_date());
+    ASSERT_FALSE(value.check_date());
     value._month = 2;
 
     value._day = 0;
-    ASSERT_TRUE(value.check_date());
+    ASSERT_FALSE(value.check_date());
     value._year = 1987;
     value._day = 29;
     ASSERT_TRUE(value.check_date());
@@ -1185,6 +1185,7 @@ TEST_F(DateTimeValueTest, from_int_value) {
 // Construct from int value invalid
 TEST_F(DateTimeValueTest, from_int_value_invalid) {
     DateTimeValue value;
+    char str[MAX_DTVALUE_STR_LEN];
     // minus value
     ASSERT_FALSE(value.from_date_int64(-1231));
     // [0, 101)
@@ -1198,7 +1199,10 @@ TEST_F(DateTimeValueTest, from_int_value_invalid) {
     // 100-12-31
     ASSERT_FALSE(value.from_date_int64(1232));
     // 99 00:00:00
-    ASSERT_FALSE(value.from_date_int64(99000000));
+    ASSERT_TRUE(value.from_date_int64(99000000));
+    value.to_string(str);
+    ASSERT_STREQ("9900-00-00", str);
+
     // 9999-99-99 99:99:99 + 1
     ASSERT_FALSE(value.from_date_int64(99999999999999L + 1));
 }
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 257e6fd..a9cc822 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
@@ -62,6 +62,7 @@ public class DateLiteral extends LiteralExpr {
     public static final DateLiteral UNIX_EPOCH_TIME = new DateLiteral(1970, 
01, 01, 00, 00, 00);
 
     private static final int DATEKEY_LENGTH = 8;
+    private static final int MAX_MICROSECOND = 999999;
 
     private static DateTimeFormatter DATE_TIME_FORMATTER = null;
     private static DateTimeFormatter DATE_FORMATTER = null;
@@ -1035,12 +1036,35 @@ public class DateLiteral extends LiteralExpr {
                 this.type = Type.DATE;
             }
         }
+
+        if (checkRange() || checkDate()) {
+            throw new InvalidFormatException("Invalid format");
+        }
         return 0;
     }
 
+    private boolean checkRange() {
+        return year > MAX_DATETIME.year || month > MAX_DATETIME.month || day > 
MAX_DATETIME.day
+                || hour > MAX_DATETIME.hour || minute > MAX_DATETIME.minute || 
second > MAX_DATETIME.second
+                || microsecond > MAX_MICROSECOND;
+    }
+    private boolean checkDate() {
+        if (month != 0 && day > DAYS_IN_MONTH.get((int)month)){
+            if (month == 2 && day == 29 && Year.isLeap(year)) {
+                return false;
+            }
+            return true;
+        }
+        return false;
+    }
+
     private long strToLong(String l) throws InvalidFormatException {
         try {
-            return Long.valueOf(l);
+            long y = Long.valueOf(l);
+            if (y < 0) {
+                throw new InvalidFormatException("Invalid format: negative 
number.");
+            }
+            return y;
         } catch (NumberFormatException e) {
             throw new InvalidFormatException(e.getMessage());
         }
diff --git 
a/fe/fe-core/src/test/java/org/apache/doris/analysis/DateLiteralTest.java 
b/fe/fe-core/src/test/java/org/apache/doris/analysis/DateLiteralTest.java
index 02b165b..9b94f9d 100644
--- a/fe/fe-core/src/test/java/org/apache/doris/analysis/DateLiteralTest.java
+++ b/fe/fe-core/src/test/java/org/apache/doris/analysis/DateLiteralTest.java
@@ -19,6 +19,8 @@ package org.apache.doris.analysis;
 
 import org.apache.doris.catalog.Type;
 import org.apache.doris.common.AnalysisException;
+import org.apache.doris.common.InvalidFormatException;
+import org.apache.doris.common.jmockit.Deencapsulation;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -74,4 +76,43 @@ public class DateLiteralTest {
         }
         Assert.assertFalse(hasException);
     }
+
+    @Test
+    public void testCheckDate() {
+        boolean hasException = false;
+        try {
+            DateLiteral dateLiteral = new DateLiteral();
+            dateLiteral.fromDateFormatStr("%Y%m%d","19971007", false);
+            Assert.assertFalse(Deencapsulation.invoke(dateLiteral, 
"checkDate"));
+
+            dateLiteral.fromDateFormatStr("%Y%m%d","19970007", false);
+            Assert.assertFalse(Deencapsulation.invoke(dateLiteral, 
"checkDate"));
+
+            dateLiteral.fromDateFormatStr("%Y%m%d","19971000", false);
+            Assert.assertFalse(Deencapsulation.invoke(dateLiteral, 
"checkDate"));
+
+            dateLiteral.fromDateFormatStr("%Y%m%d","20000229", false);
+            Assert.assertFalse(Deencapsulation.invoke(dateLiteral, 
"checkDate"));
+
+        } catch (InvalidFormatException e) {
+            e.printStackTrace();
+            hasException = true;
+        }
+        Assert.assertFalse(hasException);
+    }
+
+    @Test
+    public void testCheckRange() {
+        boolean hasException = false;
+        try {
+            DateLiteral dateLiteral = new DateLiteral();
+            
dateLiteral.fromDateFormatStr("%Y%m%d%H%i%s%f","20201209123456123456", false);
+            Assert.assertFalse(Deencapsulation.invoke(dateLiteral, 
"checkRange"));
+
+        } catch (InvalidFormatException e) {
+            e.printStackTrace();
+            hasException = true;
+        }
+        Assert.assertFalse(hasException);
+    }
 }


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

Reply via email to