Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions be/src/vec/functions/date_time_transforms.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include "vec/data_types/data_type_decimal.h"
#include "vec/data_types/data_type_string.h"
#include "vec/functions/date_format_type.h"
#include "vec/runtime/time_value.h"
#include "vec/runtime/vdatetime_value.h"
#include "vec/utils/util.hpp"

Expand Down Expand Up @@ -427,6 +428,76 @@ struct FromUnixTimeDecimalImpl {
}
};

template <PrimitiveType ArgPType>
class FunctionTimeFormat : public IFunction {
public:
using ArgColType = typename PrimitiveTypeTraits<ArgPType>::ColumnType;
using ArgCppType = typename PrimitiveTypeTraits<ArgPType>::CppType;

static constexpr auto name = "time_format";
String get_name() const override { return name; }
static FunctionPtr create() { return std::make_shared<FunctionTimeFormat>(); }
DataTypes get_variadic_argument_types_impl() const override {
return {std::make_shared<typename PrimitiveTypeTraits<ArgPType>::DataType>(),
std::make_shared<vectorized::DataTypeString>()};
}
DataTypePtr get_return_type_impl(const ColumnsWithTypeAndName& arguments) const override {
return make_nullable(std::make_shared<DataTypeString>());
}
size_t get_number_of_arguments() const override { return 2; }

Status execute_impl(FunctionContext* context, Block& block, const ColumnNumbers& arguments,
uint32_t result, size_t input_rows_count) const override {
auto res_col = ColumnString::create();
ColumnString::Chars& res_chars = res_col->get_chars();
ColumnString::Offsets& res_offsets = res_col->get_offsets();

auto null_map = ColumnUInt8::create();
auto& null_map_data = null_map->get_data();
null_map_data.resize_fill(input_rows_count, 0);

res_offsets.reserve(input_rows_count);

ColumnPtr arg_col[2];
bool is_const[2];
for (size_t i = 0; i < 2; ++i) {
const ColumnPtr& col = block.get_by_position(arguments[i]).column;
std::tie(arg_col[i], is_const[i]) = unpack_if_const(col);
}

const auto* datetime_col = assert_cast<const ArgColType*>(arg_col[0].get());
const auto* format_col = assert_cast<const ColumnString*>(arg_col[1].get());
for (size_t i = 0; i < input_rows_count; ++i) {
const auto& datetime_val = datetime_col->get_element(index_check_const(i, is_const[0]));
StringRef format = format_col->get_data_at(index_check_const(i, is_const[1]));
TimeValue::TimeType time = get_time_value(datetime_val);

char buf[100 + SAFE_FORMAT_STRING_MARGIN];
if (!TimeValue::to_format_string_conservative(format.data, format.size, buf,
100 + SAFE_FORMAT_STRING_MARGIN, time)) {
null_map_data[i] = 1;
res_offsets.push_back(res_chars.size());
continue;
}
res_chars.insert(buf, buf + strlen(buf));
res_offsets.push_back(res_chars.size());
}
block.replace_by_position(result,
ColumnNullable::create(std::move(res_col), std::move(null_map)));
return Status::OK();
}

private:
TimeValue::TimeType get_time_value(const ArgCppType& datetime_val) const {
if constexpr (ArgPType == PrimitiveType::TYPE_TIMEV2) {
return static_cast<TimeValue::TimeType>(datetime_val);
} else {
return TimeValue::make_time(datetime_val.hour(), datetime_val.minute(),
datetime_val.second(), datetime_val.microsecond());
}
}
};

#include "common/compile_check_end.h"
} // namespace doris::vectorized

Expand Down
6 changes: 6 additions & 0 deletions be/src/vec/functions/function_datetime_string_to_string.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ using FunctionFromUnixTimeNewDecimalOneArg =
FunctionDateTimeStringToString<FromUnixTimeDecimalImpl<false>>;
using FunctionFromUnixTimeNewDecimalTwoArg =
FunctionDateTimeStringToString<FromUnixTimeDecimalImpl<true>>;
using FunctionTimeFormatDate = FunctionTimeFormat<TYPE_DATEV2>;
using FunctionTimeFormatDateTime = FunctionTimeFormat<TYPE_DATETIMEV2>;
using FunctionTimeFormatTime = FunctionTimeFormat<TYPE_TIMEV2>;

void register_function_date_time_string_to_string(SimpleFunctionFactory& factory) {
factory.register_function<FunctionDateFormatV2>();
Expand All @@ -47,6 +50,9 @@ void register_function_date_time_string_to_string(SimpleFunctionFactory& factory
factory.register_function<FunctionFromUnixTimeNewDecimalOneArg>();
factory.register_function<FunctionFromUnixTimeNewDecimalTwoArg>();
factory.register_function<FunctionDateTimeV2DateFormat>();
factory.register_function<FunctionTimeFormatDate>();
factory.register_function<FunctionTimeFormatDateTime>();
factory.register_function<FunctionTimeFormatTime>();
}

} // namespace doris::vectorized
16 changes: 16 additions & 0 deletions be/src/vec/runtime/time_value.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "runtime/define_primitive_type.h"
#include "runtime/primitive_type.h"
#include "util/date_func.h"
#include "vec/runtime/vdatetime_value.h"

namespace doris {
#include "common/compile_check_begin.h"
Expand Down Expand Up @@ -150,6 +151,21 @@ class TimeValue {
}

static bool valid(double time) { return time <= MAX_TIME && time >= -MAX_TIME; }

static bool to_format_string_conservative(const char* format, size_t len, char* to,
size_t max_valid_length, TimeType time) {
// If time is negative, we here only add a '-' to the begining of res
// This behavior is consistent with MySQL
if (time < 0) {
memcpy(to, "-", 1);
++to;
time = -time;
}

return DatetimeValueUtil::to_format_string_without_check<true>(
format, len, to, max_valid_length, 0, 0, 0, TimeValue::hour(time),
TimeValue::minute(time), TimeValue::second(time), TimeValue::microsecond(time));
}
};
} // namespace doris
#include "common/compile_check_end.h"
Loading