From 5215727b453fe856afea591195908f83cfeeece8 Mon Sep 17 00:00:00 2001 From: Mingyu Chen Date: Thu, 3 Dec 2020 09:33:26 +0800 Subject: [PATCH] [Function] Let "str_to_date" return correct type (#5004) The return type of str_to_date depends on whether the time part is included in the format. If included, it is DATETIME, otherwise it is DATE. If the format parameter is not constant, the return type will be DATETIME. The above judgment has been completed in the FE query planning stage, so here we directly set the value type to the return type set in the query plan. For example: A table with one column k1 varchar, and has 2 lines: "%Y-%m-%d" "%Y-%m-%d %H:%i:%s" Query: SELECT str_to_date("2020-09-01", k1) from tbl; Result will be: 2020-09-01 00:00:00 2020-09-01 00:00:00 Query: SELECT str_to_date("2020-09-01", "%Y-%m-%d"); Return type is DATE Query: SELECT str_to_date("2020-09-01", "%Y-%m-%d %H:%i:%s"); Return type is DATETIME --- be/src/exprs/timestamp_functions.cpp | 20 +++++++++ be/src/udf/udf_internal.h | 2 + .../apache/doris/analysis/DateLiteral.java | 6 ++- .../doris/analysis/FunctionCallExpr.java | 42 ++++++++++++++++++- 4 files changed, 68 insertions(+), 2 deletions(-) diff --git a/be/src/exprs/timestamp_functions.cpp b/be/src/exprs/timestamp_functions.cpp index 57b5b808f2..cefd2eb762 100644 --- a/be/src/exprs/timestamp_functions.cpp +++ b/be/src/exprs/timestamp_functions.cpp @@ -203,6 +203,26 @@ DateTimeVal TimestampFunctions::str_to_date(FunctionContext* ctx, const StringVa str.len)) { return DateTimeVal::null(); } + + /// The return type of str_to_date depends on whether the time part is included in the format. + /// If included, it is datetime, otherwise it is date. + /// If the format parameter is not constant, the return type will be datetime. + /// The above judgment has been completed in the FE query planning stage, + /// so here we directly set the value type to the return type set in the query plan. + /// + /// For example: + /// A table with one column k1 varchar, and has 2 lines: + /// "%Y-%m-%d" + /// "%Y-%m-%d %H:%i:%s" + /// Query: + /// SELECT str_to_date("2020-09-01", k1) from tbl; + /// Result will be: + /// 2020-09-01 00:00:00 + /// 2020-09-01 00:00:00 + if (ctx->impl()->get_return_type().type == doris_udf::FunctionContext::Type::TYPE_DATETIME) { + ts_value.to_datetime(); + } + DateTimeVal ts_val; ts_value.to_datetime_val(&ts_val); return ts_val; diff --git a/be/src/udf/udf_internal.h b/be/src/udf/udf_internal.h index ba6f78d3c9..ed6b37de5f 100644 --- a/be/src/udf/udf_internal.h +++ b/be/src/udf/udf_internal.h @@ -102,6 +102,8 @@ public: std::string& string_result() { return _string_result; } + const doris_udf::FunctionContext::TypeDesc& get_return_type() const { return _return_type; } + private: friend class doris_udf::FunctionContext; friend class ExprContext; 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 e3fd359430..4025c61027 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 @@ -498,7 +498,7 @@ public class DateLiteral extends LiteralExpr { dateTime.getHourOfDay(), dateTime.getMinuteOfHour(), dateTime.getSecondOfMinute()); - if(HAS_TIME_PART.matcher(pattern).matches()) { + if (HAS_TIME_PART.matcher(pattern).matches()) { dateLiteral.setType(Type.DATETIME); } else { dateLiteral.setType(Type.DATE); @@ -506,6 +506,10 @@ public class DateLiteral extends LiteralExpr { return dateLiteral; } + public static boolean hasTimePart(String format) { + return HAS_TIME_PART.matcher(format).matches(); + } + //Return the date stored in the dateliteral as pattern format. //eg : "%Y-%m-%d" or "%Y-%m-%d %H:%i:%s" public String dateFormat(String pattern) throws AnalysisException { diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/FunctionCallExpr.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/FunctionCallExpr.java index 074d4f7400..0b0ef1bcc4 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/FunctionCallExpr.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/FunctionCallExpr.java @@ -646,7 +646,46 @@ public class FunctionCallExpr extends Expr { } } } - this.type = fn.getReturnType(); + + /** + * The return type of str_to_date depends on whether the time part is included in the format. + * If included, it is datetime, otherwise it is date. + * If the format parameter is not constant, the return type will be datetime. + * The above judgment has been completed in the FE query planning stage, + * so here we directly set the value type to the return type set in the query plan. + * + * For example: + * A table with one column k1 varchar, and has 2 lines: + * "%Y-%m-%d" + * "%Y-%m-%d %H:%i:%s" + * Query: + * SELECT str_to_date("2020-09-01", k1) from tbl; + * Result will be: + * 2020-09-01 00:00:00 + * 2020-09-01 00:00:00 + * + * Query: + * SELECT str_to_date("2020-09-01", "%Y-%m-%d"); + * Return type is DATE + * + * Query: + * SELECT str_to_date("2020-09-01", "%Y-%m-%d %H:%i:%s"); + * Return type is DATETIME + */ + if (fn.getFunctionName().getFunction().equals("str_to_date")) { + Expr child1Result = getChild(1).getResultValue(); + if (child1Result instanceof StringLiteral) { + if (DateLiteral.hasTimePart(((StringLiteral) child1Result).getStringValue())) { + this.type = Type.DATETIME; + } else { + this.type = Type.DATE; + } + } else { + this.type = Type.DATETIME; + } + } else { + this.type = fn.getReturnType(); + } } @Override @@ -734,3 +773,4 @@ public class FunctionCallExpr extends Expr { return result; } } +