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 <gabrielleeb...@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-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org