diff --git a/extension/icu/icu-datefunc.cpp b/extension/icu/icu-datefunc.cpp index 81006b2cfb7..f7c842e4f24 100644 --- a/extension/icu/icu-datefunc.cpp +++ b/extension/icu/icu-datefunc.cpp @@ -13,22 +13,34 @@ ICUDateFunc::BindData::BindData(const BindData &other) : tz_setting(other.tz_setting), cal_setting(other.cal_setting), calendar(other.calendar->clone()) { } +ICUDateFunc::BindData::BindData(const string &tz_setting_p, const string &cal_setting_p) + : tz_setting(tz_setting_p), cal_setting(cal_setting_p) { + + InitCalendar(); +} + ICUDateFunc::BindData::BindData(ClientContext &context) { Value tz_value; if (context.TryGetCurrentSetting("TimeZone", tz_value)) { tz_setting = tz_value.ToString(); } - auto tz = icu::TimeZone::createTimeZone(icu::UnicodeString::fromUTF8(icu::StringPiece(tz_setting))); - string cal_id("@calendar="); Value cal_value; if (context.TryGetCurrentSetting("Calendar", cal_value)) { cal_setting = cal_value.ToString(); - cal_id += cal_setting; } else { - cal_id += "gregorian"; + cal_setting = "gregorian"; } + InitCalendar(); +} + +void ICUDateFunc::BindData::InitCalendar() { + auto tz = icu::TimeZone::createTimeZone(icu::UnicodeString::fromUTF8(icu::StringPiece(tz_setting))); + + string cal_id("@calendar="); + cal_id += cal_setting; + icu::Locale locale(cal_id.c_str()); UErrorCode success = U_ZERO_ERROR; diff --git a/extension/icu/icu-datepart.cpp b/extension/icu/icu-datepart.cpp index 8437de9b757..ce794e774bc 100644 --- a/extension/icu/icu-datepart.cpp +++ b/extension/icu/icu-datepart.cpp @@ -327,8 +327,13 @@ struct ICUDatePart : public ICUDateFunc { using bigints_t = vector; using doubles_t = vector; - BindStructData(ClientContext &context, part_codes_t &part_codes_p, bigints_t &bigints_p, doubles_t &doubles_p) - : BindData(context), part_codes(part_codes_p), bigints(bigints_p), doubles(doubles_p) { + BindStructData(ClientContext &context, part_codes_t &&part_codes_p) + : BindData(context), part_codes(part_codes_p) { + InitFactories(); + } + BindStructData(const string &tz_setting_p, const string &cal_setting_p, part_codes_t &&part_codes_p) + : BindData(tz_setting_p, cal_setting_p), part_codes(part_codes_p) { + InitFactories(); } BindStructData(const BindStructData &other) : BindData(other), part_codes(other.part_codes), bigints(other.bigints), doubles(other.doubles) { @@ -340,13 +345,27 @@ struct ICUDatePart : public ICUDateFunc { bool Equals(const FunctionData &other_p) const override { const auto &other = other_p.Cast(); - return BindData::Equals(other_p) && part_codes == other.part_codes && bigints == other.bigints && - doubles == other.doubles; + return BindData::Equals(other_p) && part_codes == other.part_codes; } duckdb::unique_ptr Copy() const override { return make_uniq(*this); } + + void InitFactories() { + bigints.clear(); + bigints.resize(part_codes.size(), nullptr); + doubles.clear(); + doubles.resize(part_codes.size(), nullptr); + for (size_t col = 0; col < part_codes.size(); ++col) { + const auto part_code = part_codes[col]; + if (IsBigintDatepart(part_code)) { + bigints[col] = PartCodeBigintFactory(part_code); + } else { + doubles[col] = PartCodeDoubleFactory(part_code); + } + } + } }; template @@ -504,8 +523,6 @@ struct ICUDatePart : public ICUDateFunc { case_insensitive_set_t name_collision_set; child_list_t struct_children; BindStructData::part_codes_t part_codes; - BindStructData::bigints_t bigints; - BindStructData::doubles_t doubles; Value parts_list = ExpressionExecutor::EvaluateScalar(context, *arguments[0]); if (parts_list.type().id() == LogicalTypeId::LIST) { @@ -514,8 +531,6 @@ struct ICUDatePart : public ICUDateFunc { throw BinderException("%s requires non-empty lists of part names", bound_function.name); } - bigints.resize(list_children.size(), nullptr); - doubles.resize(list_children.size(), nullptr); for (size_t col = 0; col < list_children.size(); ++col) { const auto &part_value = list_children[col]; if (part_value.IsNull()) { @@ -529,10 +544,8 @@ struct ICUDatePart : public ICUDateFunc { name_collision_set.insert(part_name); part_codes.emplace_back(part_code); if (IsBigintDatepart(part_code)) { - bigints[col] = PartCodeBigintFactory(part_code); struct_children.emplace_back(make_pair(part_name, LogicalType::BIGINT)); } else { - doubles[col] = PartCodeDoubleFactory(part_code); struct_children.emplace_back(make_pair(part_name, LogicalType::DOUBLE)); } } @@ -542,17 +555,24 @@ struct ICUDatePart : public ICUDateFunc { Function::EraseArgument(bound_function, arguments, 0); bound_function.return_type = LogicalType::STRUCT(std::move(struct_children)); - return make_uniq(context, part_codes, bigints, doubles); + return make_uniq(context, std::move(part_codes)); } - static void SerializeFunction(Serializer &serializer, const optional_ptr bind_data, - const ScalarFunction &function) { - throw NotImplementedException("FIXME: serialize icu-datepart"); + static void SerializeStructFunction(Serializer &serializer, const optional_ptr bind_data, + const ScalarFunction &function) { + D_ASSERT(bind_data); + auto &info = bind_data->Cast(); + serializer.WriteProperty(100, "tz_setting", info.tz_setting); + serializer.WriteProperty(101, "cal_setting", info.cal_setting); + serializer.WriteProperty(102, "part_codes", info.part_codes); } - static duckdb::unique_ptr DeserializeFunction(Deserializer &deserializer, - ScalarFunction &bound_function) { - throw NotImplementedException("FIXME: serialize icu-datepart"); + static duckdb::unique_ptr DeserializeStructFunction(Deserializer &deserializer, + ScalarFunction &bound_function) { + auto tz_setting = deserializer.ReadProperty(100, "tz_setting"); + auto cal_setting = deserializer.ReadProperty(101, "cal_setting"); + auto part_codes = deserializer.ReadProperty>(102, "part_codes"); + return make_uniq(tz_setting, cal_setting, std::move(part_codes)); } template @@ -581,8 +601,8 @@ struct ICUDatePart : public ICUDateFunc { auto part_type = LogicalType::LIST(LogicalType::VARCHAR); auto result_type = LogicalType::STRUCT({}); ScalarFunction result({part_type, temporal_type}, result_type, StructFunction, BindStruct); - result.serialize = SerializeFunction; - result.deserialize = DeserializeFunction; + result.serialize = SerializeStructFunction; + result.deserialize = DeserializeStructFunction; return result; } diff --git a/extension/icu/include/icu-datefunc.hpp b/extension/icu/include/icu-datefunc.hpp index 08a96f099f2..1ae2a5f12ce 100644 --- a/extension/icu/include/icu-datefunc.hpp +++ b/extension/icu/include/icu-datefunc.hpp @@ -21,6 +21,7 @@ struct ICUDateFunc { struct BindData : public FunctionData { explicit BindData(ClientContext &context); + BindData(const string &tz_setting, const string &cal_setting); BindData(const BindData &other); string tz_setting; @@ -29,6 +30,8 @@ struct ICUDateFunc { bool Equals(const FunctionData &other_p) const override; duckdb::unique_ptr Copy() const override; + + void InitCalendar(); }; struct CastData : public BoundCastData {