From 6fe2a30e5679e55e8ac6480a3df5c981e01ee8ca Mon Sep 17 00:00:00 2001 From: aceforeverd Date: Mon, 23 Oct 2023 21:43:22 +0800 Subject: [PATCH] fix(codegen): handle nullable for date type (#3543) * fix(codegen): handle nullable for date type Also fix include headers * fix(codegen): handle nulls for date and timestamp always returns allocated structure even it is null, for the cases: 1. construct timestamp from number, even number is < 0 2. construct date from timestamp, even timestamp is null --- cases/query/const_query.yaml | 12 +++++++++ hybridse/src/codegen/array_ir_builder.cc | 1 + hybridse/src/codegen/cast_expr_ir_builder.cc | 5 ++++ hybridse/src/codegen/date_ir_builder.cc | 19 ++++++++++---- hybridse/src/codegen/date_ir_builder.h | 22 +++++++--------- hybridse/src/codegen/ir_base_builder.h | 1 - hybridse/src/codegen/native_value.cc | 1 - .../src/codegen/predicate_expr_ir_builder.cc | 1 + hybridse/src/codegen/struct_ir_builder.h | 6 ++--- hybridse/src/codegen/timestamp_ir_builder.cc | 26 ++++++++++--------- hybridse/src/codegen/timestamp_ir_builder.h | 9 +++---- hybridse/src/codegen/type_ir_builder.cc | 1 + hybridse/src/codegen/type_ir_builder.h | 7 +++-- hybridse/src/codegen/udf_ir_builder.cc | 12 ++++----- hybridse/src/codegen/udf_ir_builder.h | 4 --- hybridse/src/udf/default_udf_library.cc | 13 ++-------- hybridse/src/udf/udf.cc | 15 +++-------- hybridse/src/udf/udf.h | 4 --- 18 files changed, 76 insertions(+), 83 deletions(-) diff --git a/cases/query/const_query.yaml b/cases/query/const_query.yaml index 38bbbeb5e47..5efe6fa3c29 100644 --- a/cases/query/const_query.yaml +++ b/cases/query/const_query.yaml @@ -126,3 +126,15 @@ cases: columns: ['c1 bool', 'c2 int16', 'c3 int', 'c4 double', 'c5 string', 'c6 date', 'c7 timestamp' ] rows: - [ true, 3, 13, 10.0, 'a string', '2020-05-22', 1590115420000 ] + - id: 10 + mode: procedure-unsupport + sql: | + select + datediff(Date(timestamp(-1)), Date("2021-05-01")) as out1, + datediff(Date(timestamp(-2177481600)), Date("2021-05-01")) as out2, + datediff(cast(NULL as date), Date("2021-05-01")) as out3 + ; + expect: + columns: ["out1 int", "out2 int", "out3 int"] + data: | + NULL, NULL, NULL diff --git a/hybridse/src/codegen/array_ir_builder.cc b/hybridse/src/codegen/array_ir_builder.cc index f07f551caf1..0788c1ba8aa 100644 --- a/hybridse/src/codegen/array_ir_builder.cc +++ b/hybridse/src/codegen/array_ir_builder.cc @@ -17,6 +17,7 @@ #include "codegen/array_ir_builder.h" #include +#include "codegen/ir_base_builder.h" namespace hybridse { namespace codegen { diff --git a/hybridse/src/codegen/cast_expr_ir_builder.cc b/hybridse/src/codegen/cast_expr_ir_builder.cc index 526a686ae66..bdb6329c6c8 100644 --- a/hybridse/src/codegen/cast_expr_ir_builder.cc +++ b/hybridse/src/codegen/cast_expr_ir_builder.cc @@ -126,6 +126,11 @@ Status CastExprIRBuilder::UnSafeCast(const NativeValue& value, StringIRBuilder string_ir_builder(block_->getModule()); CHECK_STATUS(string_ir_builder.CreateNull(block_, output)); return base::Status::OK(); + + } else if (TypeIRBuilder::IsDatePtr(type)) { + DateIRBuilder date_ir(block_->getModule()); + CHECK_STATUS(date_ir.CreateNull(block_, output)); + return base::Status::OK(); } else { *output = NativeValue::CreateNull(type); } diff --git a/hybridse/src/codegen/date_ir_builder.cc b/hybridse/src/codegen/date_ir_builder.cc index 65c439fd143..3a60147bd9a 100644 --- a/hybridse/src/codegen/date_ir_builder.cc +++ b/hybridse/src/codegen/date_ir_builder.cc @@ -19,6 +19,7 @@ #include #include "codegen/arithmetic_expr_ir_builder.h" #include "codegen/ir_base_builder.h" +#include "codegen/null_ir_builder.h" namespace hybridse { namespace codegen { @@ -43,6 +44,15 @@ void DateIRBuilder::InitStructType() { struct_type_ = stype; return; } + +base::Status DateIRBuilder::CreateNull(::llvm::BasicBlock* block, NativeValue* output) { + ::llvm::Value* value = nullptr; + CHECK_TRUE(CreateDefault(block, &value), common::kCodegenError, "Fail to construct string") + ::llvm::IRBuilder<> builder(block); + *output = NativeValue::CreateWithFlag(value, builder.getInt1(true)); + return base::Status::OK(); +} + bool DateIRBuilder::CreateDefault(::llvm::BasicBlock* block, ::llvm::Value** output) { return NewDate(block, output); @@ -123,11 +133,10 @@ base::Status DateIRBuilder::CastFrom(::llvm::BasicBlock* block, auto cast_func = m_->getOrInsertFunction( fn_name, ::llvm::FunctionType::get(builder.getVoidTy(), - {src.GetType(), dist->getType(), - builder.getInt1Ty()->getPointerTo()}, - false)); - builder.CreateCall(cast_func, - {src.GetValue(&builder), dist, is_null_ptr}); + {src.GetType(), dist->getType(), builder.getInt1Ty()->getPointerTo()}, false)); + + builder.CreateCall(cast_func, {src.GetValue(&builder), dist, is_null_ptr}); + ::llvm::Value* should_return_null = builder.CreateLoad(is_null_ptr); null_ir_builder.CheckAnyNull(block, src, &should_return_null); *output = NativeValue::CreateWithFlag(dist, should_return_null); diff --git a/hybridse/src/codegen/date_ir_builder.h b/hybridse/src/codegen/date_ir_builder.h index cb41dc5f263..b44b039d57d 100644 --- a/hybridse/src/codegen/date_ir_builder.h +++ b/hybridse/src/codegen/date_ir_builder.h @@ -16,13 +16,9 @@ #ifndef HYBRIDSE_SRC_CODEGEN_DATE_IR_BUILDER_H_ #define HYBRIDSE_SRC_CODEGEN_DATE_IR_BUILDER_H_ + #include "base/fe_status.h" -#include "codegen/cast_expr_ir_builder.h" -#include "codegen/null_ir_builder.h" -#include "codegen/scope_var.h" #include "codegen/struct_ir_builder.h" -#include "llvm/IR/IRBuilder.h" -#include "proto/fe_type.pb.h" namespace hybridse { namespace codegen { @@ -31,17 +27,17 @@ class DateIRBuilder : public StructTypeIRBuilder { public: explicit DateIRBuilder(::llvm::Module* m); ~DateIRBuilder(); - void InitStructType(); - bool CreateDefault(::llvm::BasicBlock* block, ::llvm::Value** output); + void InitStructType() override; + + base::Status CreateNull(::llvm::BasicBlock* block, NativeValue* output); + bool CreateDefault(::llvm::BasicBlock* block, ::llvm::Value** output) override; + bool NewDate(::llvm::BasicBlock* block, ::llvm::Value** output); bool NewDate(::llvm::BasicBlock* block, ::llvm::Value* date, ::llvm::Value** output); - bool CopyFrom(::llvm::BasicBlock* block, ::llvm::Value* src, - ::llvm::Value* dist); - base::Status CastFrom(::llvm::BasicBlock* block, const NativeValue& src, - NativeValue* output); - base::Status CastFrom(::llvm::BasicBlock* block, ::llvm::Value* src, - ::llvm::Value** output); + bool CopyFrom(::llvm::BasicBlock* block, ::llvm::Value* src, ::llvm::Value* dist); + base::Status CastFrom(::llvm::BasicBlock* block, const NativeValue& src, NativeValue* output); + bool GetDate(::llvm::BasicBlock* block, ::llvm::Value* date, ::llvm::Value** output); bool SetDate(::llvm::BasicBlock* block, ::llvm::Value* date, diff --git a/hybridse/src/codegen/ir_base_builder.h b/hybridse/src/codegen/ir_base_builder.h index c52bba23431..db2075289cf 100644 --- a/hybridse/src/codegen/ir_base_builder.h +++ b/hybridse/src/codegen/ir_base_builder.h @@ -19,7 +19,6 @@ #include #include -#include "glog/logging.h" #include "llvm/IR/IRBuilder.h" #include "node/sql_node.h" #include "node/type_node.h" diff --git a/hybridse/src/codegen/native_value.cc b/hybridse/src/codegen/native_value.cc index c4c6e2e562a..fce4f0bb5bb 100644 --- a/hybridse/src/codegen/native_value.cc +++ b/hybridse/src/codegen/native_value.cc @@ -17,7 +17,6 @@ #include "codegen/native_value.h" #include #include -#include #include "codegen/context.h" #include "codegen/ir_base_builder.h" diff --git a/hybridse/src/codegen/predicate_expr_ir_builder.cc b/hybridse/src/codegen/predicate_expr_ir_builder.cc index aaf0fb0753c..45ed8f7ec21 100644 --- a/hybridse/src/codegen/predicate_expr_ir_builder.cc +++ b/hybridse/src/codegen/predicate_expr_ir_builder.cc @@ -17,6 +17,7 @@ #include "codegen/predicate_expr_ir_builder.h" #include "codegen/date_ir_builder.h" #include "codegen/ir_base_builder.h" +#include "codegen/null_ir_builder.h" #include "codegen/string_ir_builder.h" #include "codegen/timestamp_ir_builder.h" #include "codegen/type_ir_builder.h" diff --git a/hybridse/src/codegen/struct_ir_builder.h b/hybridse/src/codegen/struct_ir_builder.h index 2f1f94d036c..e306dfe869e 100644 --- a/hybridse/src/codegen/struct_ir_builder.h +++ b/hybridse/src/codegen/struct_ir_builder.h @@ -16,12 +16,10 @@ #ifndef HYBRIDSE_SRC_CODEGEN_STRUCT_IR_BUILDER_H_ #define HYBRIDSE_SRC_CODEGEN_STRUCT_IR_BUILDER_H_ + #include "base/fe_status.h" -#include "codegen/cast_expr_ir_builder.h" -#include "codegen/scope_var.h" +#include "codegen/native_value.h" #include "codegen/type_ir_builder.h" -#include "llvm/IR/IRBuilder.h" -#include "proto/fe_type.pb.h" namespace hybridse { namespace codegen { diff --git a/hybridse/src/codegen/timestamp_ir_builder.cc b/hybridse/src/codegen/timestamp_ir_builder.cc index 13d6e065f39..f14952f455c 100644 --- a/hybridse/src/codegen/timestamp_ir_builder.cc +++ b/hybridse/src/codegen/timestamp_ir_builder.cc @@ -15,14 +15,15 @@ */ #include "codegen/timestamp_ir_builder.h" + #include #include + #include "codegen/arithmetic_expr_ir_builder.h" #include "codegen/ir_base_builder.h" #include "codegen/null_ir_builder.h" #include "codegen/predicate_expr_ir_builder.h" #include "glog/logging.h" -#include "node/sql_node.h" using hybridse::common::kCodegenError; @@ -70,29 +71,30 @@ base::Status TimestampIRBuilder::CastFrom(::llvm::BasicBlock* block, CondSelectIRBuilder cond_ir_builder; PredicateIRBuilder predicate_ir_builder(block); NullIRBuilder null_ir_builder; + + // always allocate for returned timestmap even it is null + ::llvm::Value* dist = nullptr; + if (!CreateDefault(block, &dist)) { + status.code = common::kCodegenError; + status.msg = "Fail to cast date: create default date fail"; + return status; + } + if (IsNumber(src.GetType())) { CHECK_STATUS(cast_builder.Cast(src, builder.getInt64Ty(), &ts)); NativeValue cond; CHECK_STATUS(predicate_ir_builder.BuildGeExpr( ts, NativeValue::Create(builder.getInt64(0)), &cond)); - ::llvm::Value* timestamp; - CHECK_TRUE(NewTimestamp(block, ts.GetValue(&builder), ×tamp), + CHECK_TRUE(SetTs(block, dist, ts.GetValue(&builder)), kCodegenError, "Fail to cast timestamp: new timestamp(ts) fail"); - CHECK_STATUS( - cond_ir_builder.Select(block, cond, NativeValue::Create(timestamp), - NativeValue::CreateNull(GetType()), output)); + CHECK_STATUS(cond_ir_builder.Select(block, cond, NativeValue::Create(dist), + NativeValue::CreateWithFlag(dist, builder.getInt1(true)), output)); } else if (IsStringPtr(src.GetType()) || IsDatePtr(src.GetType())) { ::llvm::IRBuilder<> builder(block); - ::llvm::Value* dist = nullptr; ::llvm::Value* is_null_ptr = CreateAllocaAtHead( &builder, builder.getInt1Ty(), "timestamp_is_null_alloca"); - if (!CreateDefault(block, &dist)) { - status.code = common::kCodegenError; - status.msg = "Fail to cast date: create default date fail"; - return status; - } ::std::string fn_name = "timestamp." + TypeName(src.GetType()); auto cast_func = m_->getOrInsertFunction( diff --git a/hybridse/src/codegen/timestamp_ir_builder.h b/hybridse/src/codegen/timestamp_ir_builder.h index 33de3cce2e5..84051979597 100644 --- a/hybridse/src/codegen/timestamp_ir_builder.h +++ b/hybridse/src/codegen/timestamp_ir_builder.h @@ -16,12 +16,9 @@ #ifndef HYBRIDSE_SRC_CODEGEN_TIMESTAMP_IR_BUILDER_H_ #define HYBRIDSE_SRC_CODEGEN_TIMESTAMP_IR_BUILDER_H_ + #include "base/fe_status.h" -#include "codegen/cast_expr_ir_builder.h" -#include "codegen/scope_var.h" #include "codegen/struct_ir_builder.h" -#include "llvm/IR/IRBuilder.h" -#include "proto/fe_type.pb.h" namespace hybridse { namespace codegen { @@ -33,8 +30,8 @@ class TimestampIRBuilder : public StructTypeIRBuilder { void InitStructType(); bool CreateDefault(::llvm::BasicBlock* block, ::llvm::Value** output); bool NewTimestamp(::llvm::BasicBlock* block, ::llvm::Value** output); - bool NewTimestamp(::llvm::BasicBlock* block, ::llvm::Value* ts, - ::llvm::Value** output); + bool NewTimestamp(::llvm::BasicBlock* block, ::llvm::Value* ts, ::llvm::Value** output); + bool CopyFrom(::llvm::BasicBlock* block, ::llvm::Value* src, ::llvm::Value* dist); base::Status CastFrom(::llvm::BasicBlock* block, const NativeValue& src, diff --git a/hybridse/src/codegen/type_ir_builder.cc b/hybridse/src/codegen/type_ir_builder.cc index 3fcd5891c4c..bbdf1346995 100644 --- a/hybridse/src/codegen/type_ir_builder.cc +++ b/hybridse/src/codegen/type_ir_builder.cc @@ -15,6 +15,7 @@ */ #include "codegen/type_ir_builder.h" + #include "codegen/ir_base_builder.h" #include "glog/logging.h" #include "node/node_manager.h" diff --git a/hybridse/src/codegen/type_ir_builder.h b/hybridse/src/codegen/type_ir_builder.h index e06e77244e6..ad7d5f225b9 100644 --- a/hybridse/src/codegen/type_ir_builder.h +++ b/hybridse/src/codegen/type_ir_builder.h @@ -18,11 +18,10 @@ #define HYBRIDSE_SRC_CODEGEN_TYPE_IR_BUILDER_H_ #include -#include + #include "base/fe_status.h" -#include "codec/fe_row_codec.h" -#include "codegen/ir_base_builder.h" -#include "node/node_enum.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Type.h" #include "node/sql_node.h" #include "node/type_node.h" diff --git a/hybridse/src/codegen/udf_ir_builder.cc b/hybridse/src/codegen/udf_ir_builder.cc index 6d6f967a83e..5030f3cd8ae 100644 --- a/hybridse/src/codegen/udf_ir_builder.cc +++ b/hybridse/src/codegen/udf_ir_builder.cc @@ -15,19 +15,17 @@ */ #include "codegen/udf_ir_builder.h" -#include -#include + #include + #include "codegen/context.h" -#include "codegen/date_ir_builder.h" #include "codegen/fn_ir_builder.h" +#include "codegen/ir_base_builder.h" #include "codegen/list_ir_builder.h" #include "codegen/null_ir_builder.h" -#include "codegen/timestamp_ir_builder.h" +#include "codegen/type_ir_builder.h" #include "llvm/IR/Attributes.h" -#include "node/node_manager.h" #include "node/sql_node.h" -#include "udf/udf.h" #include "udf/udf_registry.h" using ::hybridse::common::kCodegenError; @@ -162,7 +160,7 @@ Status UdfIRBuilder::BuildLambdaCall( Status UdfIRBuilder::BuildCodeGenUdfCall( const node::UdfByCodeGenDefNode* fn, const std::vector& args, NativeValue* output) { - auto gen_impl = fn->GetGenImpl(); + std::shared_ptr gen_impl = fn->GetGenImpl(); ::llvm::Value* ret_null = nullptr; for (size_t i = 0; i < fn->GetArgSize(); ++i) { diff --git a/hybridse/src/codegen/udf_ir_builder.h b/hybridse/src/codegen/udf_ir_builder.h index ed15b6432c7..9e33837bf96 100644 --- a/hybridse/src/codegen/udf_ir_builder.h +++ b/hybridse/src/codegen/udf_ir_builder.h @@ -17,13 +17,9 @@ #ifndef HYBRIDSE_SRC_CODEGEN_UDF_IR_BUILDER_H_ #define HYBRIDSE_SRC_CODEGEN_UDF_IR_BUILDER_H_ -#include -#include #include #include "base/fe_status.h" #include "codegen/expr_ir_builder.h" -#include "codegen/scope_var.h" -#include "llvm/IR/Module.h" #include "node/sql_node.h" namespace hybridse { diff --git a/hybridse/src/udf/default_udf_library.cc b/hybridse/src/udf/default_udf_library.cc index 8b98212fffb..fef776d3ffd 100644 --- a/hybridse/src/udf/default_udf_library.cc +++ b/hybridse/src/udf/default_udf_library.cc @@ -26,7 +26,6 @@ #include #include -#include "absl/strings/str_cat.h" #include "codegen/date_ir_builder.h" #include "codegen/string_ir_builder.h" #include "codegen/timestamp_ir_builder.h" @@ -2169,11 +2168,7 @@ void DefaultUdfLibrary::InitTypeUdf() { )"); RegisterExternal("date") - .args(reinterpret_cast( - static_cast( - v1::timestamp_to_date))) - .return_by_arg(true) - .returns>() + .args(v1::timestamp_to_date) .doc(R"( @brief Cast timestamp or string expression to date (date >= 1900-01-01) @@ -2192,11 +2187,7 @@ void DefaultUdfLibrary::InitTypeUdf() { @endcode @since 0.1.0)"); RegisterExternal("date") - .args(reinterpret_cast( - static_cast( - v1::string_to_date))) - .return_by_arg(true) - .returns>(); + .args(v1::string_to_date); RegisterExternal("timestamp") .args(reinterpret_cast( diff --git a/hybridse/src/udf/udf.cc b/hybridse/src/udf/udf.cc index 2ec7033472f..9326d576685 100644 --- a/hybridse/src/udf/udf.cc +++ b/hybridse/src/udf/udf.cc @@ -20,8 +20,6 @@ #include #include -#include -#include #include #include "absl/strings/ascii.h" @@ -29,20 +27,17 @@ #include "absl/time/civil_time.h" #include "absl/time/time.h" #include "base/iterator.h" -#include "boost/date_time.hpp" +#include "boost/date_time/gregorian/conversion.hpp" #include "boost/date_time/gregorian/parsers.hpp" -#include "boost/date_time/posix_time/posix_time.hpp" #include "bthread/types.h" -#include "codec/list_iterator_codec.h" #include "codec/row.h" #include "codec/type_codec.h" -#include "codegen/fn_ir_builder.h" #include "farmhash.h" #include "node/node_manager.h" #include "node/sql_node.h" #include "re2/re2.h" -#include "udf/default_udf_library.h" #include "udf/literal_traits.h" +#include "udf/udf_library.h" #include "vm/jit_runtime.h" namespace hybridse { @@ -394,8 +389,7 @@ void bool_to_string(bool v, StringRef *output) { } } -void timestamp_to_date(Timestamp *timestamp, - Date *output, bool *is_null) { +void timestamp_to_date(Timestamp *timestamp, Date *output, bool *is_null) { time_t time = (timestamp->ts_ + TZ_OFFSET) / 1000; struct tm t; memset(&t, 0, sizeof(struct tm)); @@ -771,8 +765,7 @@ void string_to_double(StringRef *str, double *out, bool *is_null_ptr) { } return; } -void string_to_date(StringRef *str, Date *output, - bool *is_null) { +void string_to_date(StringRef *str, Date *output, bool *is_null) { if (19 == str->size_) { struct tm timeinfo; memset(&timeinfo, 0, sizeof(struct tm)); diff --git a/hybridse/src/udf/udf.h b/hybridse/src/udf/udf.h index a761e99f88b..c91b78d1c90 100644 --- a/hybridse/src/udf/udf.h +++ b/hybridse/src/udf/udf.h @@ -26,10 +26,6 @@ #include "absl/strings/ascii.h" #include "base/string_ref.h" #include "base/type.h" -#include "codec/list_iterator_codec.h" -#include "codec/type_codec.h" -#include "node/node_manager.h" -#include "proto/fe_type.pb.h" #include "udf/literal_traits.h" #include "udf/openmldb_udf.h"