[Bug](date) Fix invalid date (#16205)

Issue Number: close #15777
This commit is contained in:
Gabriel
2023-01-31 10:08:44 +08:00
committed by GitHub
parent a7b030778a
commit 471db80f69
6 changed files with 95 additions and 13 deletions

View File

@ -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:

View File

@ -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) {

View File

@ -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;

View File

@ -194,6 +194,11 @@ public class StringLiteral extends LiteralExpr {
throw e;
}
}
try {
newLiteral.checkValueValid();
} catch (AnalysisException e) {
return NullLiteral.create(newLiteral.getType());
}
return newLiteral;
}

View File

@ -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

View File

@ -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}"
}