Skip to content

Commit

Permalink
Merge pull request #10055 from hawkfish/icu-serialize
Browse files Browse the repository at this point in the history
Internal #783: ICU DatePart Serializers
  • Loading branch information
Mytherin committed Jan 3, 2024
2 parents 94a43fc + 9750693 commit e61eb0c
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 23 deletions.
20 changes: 16 additions & 4 deletions extension/icu/icu-datefunc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
58 changes: 39 additions & 19 deletions extension/icu/icu-datepart.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -327,8 +327,13 @@ struct ICUDatePart : public ICUDateFunc {
using bigints_t = vector<part_bigint_t>;
using doubles_t = vector<part_double_t>;

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) {
Expand All @@ -340,13 +345,27 @@ struct ICUDatePart : public ICUDateFunc {

bool Equals(const FunctionData &other_p) const override {
const auto &other = other_p.Cast<BindStructData>();
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<FunctionData> Copy() const override {
return make_uniq<BindStructData>(*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 <typename INPUT_TYPE>
Expand Down Expand Up @@ -504,8 +523,6 @@ struct ICUDatePart : public ICUDateFunc {
case_insensitive_set_t name_collision_set;
child_list_t<LogicalType> 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) {
Expand All @@ -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()) {
Expand All @@ -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));
}
}
Expand All @@ -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<BindStructData>(context, part_codes, bigints, doubles);
return make_uniq<BindStructData>(context, std::move(part_codes));
}

static void SerializeFunction(Serializer &serializer, const optional_ptr<FunctionData> bind_data,
const ScalarFunction &function) {
throw NotImplementedException("FIXME: serialize icu-datepart");
static void SerializeStructFunction(Serializer &serializer, const optional_ptr<FunctionData> bind_data,
const ScalarFunction &function) {
D_ASSERT(bind_data);
auto &info = bind_data->Cast<BindStructData>();
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<FunctionData> DeserializeFunction(Deserializer &deserializer,
ScalarFunction &bound_function) {
throw NotImplementedException("FIXME: serialize icu-datepart");
static duckdb::unique_ptr<FunctionData> DeserializeStructFunction(Deserializer &deserializer,
ScalarFunction &bound_function) {
auto tz_setting = deserializer.ReadProperty<string>(100, "tz_setting");
auto cal_setting = deserializer.ReadProperty<string>(101, "cal_setting");
auto part_codes = deserializer.ReadProperty<vector<DatePartSpecifier>>(102, "part_codes");
return make_uniq<BindStructData>(tz_setting, cal_setting, std::move(part_codes));
}

template <typename INPUT_TYPE, typename RESULT_TYPE>
Expand Down Expand Up @@ -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<INPUT_TYPE>, BindStruct);
result.serialize = SerializeFunction;
result.deserialize = DeserializeFunction;
result.serialize = SerializeStructFunction;
result.deserialize = DeserializeStructFunction;
return result;
}

Expand Down
3 changes: 3 additions & 0 deletions extension/icu/include/icu-datefunc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -29,6 +30,8 @@ struct ICUDateFunc {

bool Equals(const FunctionData &other_p) const override;
duckdb::unique_ptr<FunctionData> Copy() const override;

void InitCalendar();
};

struct CastData : public BoundCastData {
Expand Down

0 comments on commit e61eb0c

Please sign in to comment.