Skip to content

Commit 4a1a98c

Browse files
committed
YQL-18303: Introduce StartOf/EndOf/TimeOfDay overloads
commit_hash:ed323f55ce6ca64b9a912772866d7bfb4fc1235f (cherry picked from commit 34cd625)
1 parent 86be04f commit 4a1a98c

File tree

6 files changed

+1875
-25
lines changed

6 files changed

+1875
-25
lines changed

yql/essentials/minikql/datetime/datetime64.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,18 @@ struct TTM64Storage {
148148
return true;
149149
}
150150

151+
inline void FromTimeOfDay(ui64 value) {
152+
Hour = value / 3600000000ull;
153+
value -= Hour * 3600000000ull;
154+
Minute = value / 60000000ull;
155+
value -= Minute * 60000000ull;
156+
Second = value / 1000000ull;
157+
Microsecond = value - Second * 1000000ull;
158+
}
159+
160+
inline ui64 ToTimeOfDay() const {
161+
return ((Hour * 60ull + Minute) * 60ull + Second) * 1000000ull + Microsecond;
162+
}
151163
};
152164

153165
}

yql/essentials/udfs/common/datetime2/datetime_udf.cpp

Lines changed: 252 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,13 @@ extern const char StartOfQuarterUDF[] = "StartOfQuarter";
3939
extern const char StartOfMonthUDF[] = "StartOfMonth";
4040
extern const char StartOfWeekUDF[] = "StartOfWeek";
4141
extern const char StartOfDayUDF[] = "StartOfDay";
42+
extern const char StartOfUDF[] = "StartOf";
4243
extern const char EndOfYearUDF[] = "EndOfYear";
4344
extern const char EndOfQuarterUDF[] = "EndOfQuarter";
4445
extern const char EndOfMonthUDF[] = "EndOfMonth";
4546
extern const char EndOfWeekUDF[] = "EndOfWeek";
4647
extern const char EndOfDayUDF[] = "EndOfDay";
48+
extern const char EndOfUDF[] = "EndOf";
4749
extern const char ShiftYearsUDF[] = "ShiftYears";
4850
extern const char ShiftQuartersUDF[] = "ShiftQuarters";
4951
extern const char ShiftMonthsUDF[] = "ShiftMonths";
@@ -2123,7 +2125,8 @@ class TBoundaryOf: public ::NYql::NUdf::TBoxedValue {
21232125
return storage;
21242126
}
21252127

2126-
TMaybe<TTMStorage> StartOf(TTMStorage storage, ui64 interval, const IValueBuilder& valueBuilder) {
2128+
template<typename TStorage>
2129+
TMaybe<TStorage> StartOf(TStorage storage, ui64 interval, const IValueBuilder& valueBuilder) {
21272130
if (interval >= 86400000000ull) {
21282131
// treat as StartOfDay
21292132
SetStartOfDay(storage);
@@ -2140,7 +2143,8 @@ class TBoundaryOf: public ::NYql::NUdf::TBoxedValue {
21402143
return storage;
21412144
}
21422145

2143-
TMaybe<TTMStorage> EndOf(TTMStorage storage, ui64 interval, const IValueBuilder& valueBuilder) {
2146+
template<typename TStorage>
2147+
TMaybe<TStorage> EndOf(TStorage storage, ui64 interval, const IValueBuilder& valueBuilder) {
21442148
if (interval >= 86400000000ull) {
21452149
// treat as EndOfDay
21462150
SetEndOfDay(storage);
@@ -2168,7 +2172,7 @@ class TBoundaryOf: public ::NYql::NUdf::TBoxedValue {
21682172
return;
21692173
}
21702174

2171-
if (auto res = (UseEnd ? EndOf : StartOf)(storage, interval, *valueBuilder)) {
2175+
if (auto res = (UseEnd ? EndOf<TTMStorage> : StartOf<TTMStorage>)(storage, interval, *valueBuilder)) {
21722176
storage = res.GetRef();
21732177
sink(arg1);
21742178
} else {
@@ -2177,33 +2181,141 @@ class TBoundaryOf: public ::NYql::NUdf::TBoxedValue {
21772181
}
21782182
};
21792183

2180-
BEGIN_SIMPLE_STRICT_ARROW_UDF(TStartOf, TOptional<TResource<TMResourceName>>(TAutoMap<TResource<TMResourceName>>, TAutoMap<TInterval>)) {
2184+
template<const char* TResourceName, auto Core>
2185+
TUnboxedValue SimpleDatetimeToIntervalUdf(const IValueBuilder* valueBuilder, const TUnboxedValuePod* args) {
21812186
auto result = args[0];
21822187
ui64 interval = std::abs(args[1].Get<i64>());
21832188
if (interval == 0) {
21842189
return result;
21852190
}
2186-
if (auto res = StartOf(Reference(result), interval, *valueBuilder)) {
2187-
Reference(result) = res.GetRef();
2191+
auto& storage = Reference<TResourceName>(result);
2192+
if (auto res = Core(storage, interval, *valueBuilder)) {
2193+
storage = res.GetRef();
21882194
return result;
21892195
}
21902196
return TUnboxedValuePod{};
21912197
}
2192-
END_SIMPLE_ARROW_UDF(TStartOf, TStartEndOfBinaryKernelExec<false>::Do);
21932198

2194-
BEGIN_SIMPLE_STRICT_ARROW_UDF(TEndOf, TOptional<TResource<TMResourceName>>(TAutoMap<TResource<TMResourceName>>, TAutoMap<TInterval>)) {
2195-
auto result = args[0];
2196-
ui64 interval = std::abs(args[1].Get<i64>());
2197-
if (interval == 0) {
2198-
return result;
2199+
template<const char* TUdfName, auto Boundary, auto WBoundary>
2200+
class TBoundaryOfInterval: public ::NYql::NUdf::TBoxedValue {
2201+
public:
2202+
typedef bool TTypeAwareMarker;
2203+
static const TStringRef& Name() {
2204+
static auto name = TStringRef(TUdfName, std::strlen(TUdfName));
2205+
return name;
2206+
}
2207+
2208+
static bool DeclareSignature(
2209+
const ::NYql::NUdf::TStringRef& name,
2210+
::NYql::NUdf::TType* userType,
2211+
::NYql::NUdf::IFunctionTypeInfoBuilder& builder,
2212+
bool typesOnly)
2213+
{
2214+
if (Name() != name) {
2215+
return false;
21992216
}
2200-
if (auto res = EndOf(Reference(result), interval, *valueBuilder)) {
2201-
Reference(result) = res.GetRef();
2202-
return result;
2217+
2218+
if (!userType) {
2219+
builder.SetError("User type is missing");
2220+
return true;
22032221
}
2204-
return TUnboxedValuePod{};
2222+
2223+
builder.UserType(userType);
2224+
2225+
const auto typeInfoHelper = builder.TypeInfoHelper();
2226+
TTupleTypeInspector tuple(*typeInfoHelper, userType);
2227+
Y_ENSURE(tuple, "Tuple with args and options tuples expected");
2228+
Y_ENSURE(tuple.GetElementsCount() > 0,
2229+
"Tuple has to contain positional arguments");
2230+
2231+
TTupleTypeInspector argsTuple(*typeInfoHelper, tuple.GetElementType(0));
2232+
Y_ENSURE(argsTuple, "Tuple with args expected");
2233+
if (argsTuple.GetElementsCount() != 2) {
2234+
builder.SetError("Single argument expected");
2235+
return true;
2236+
}
2237+
2238+
auto argType = argsTuple.GetElementType(0);
2239+
2240+
if (const auto optType = TOptionalTypeInspector(*typeInfoHelper, argType)) {
2241+
argType = optType.GetItemType();
2242+
}
2243+
2244+
TResourceTypeInspector resource(*typeInfoHelper, argType);
2245+
if (!resource) {
2246+
TDataTypeInspector data(*typeInfoHelper, argType);
2247+
if (!data) {
2248+
SetInvalidTypeError(builder, typeInfoHelper, argType);
2249+
return true;
2250+
}
2251+
2252+
const auto features = NUdf::GetDataTypeInfo(NUdf::GetDataSlot(data.GetTypeId())).Features;
2253+
if (features & NUdf::BigDateType) {
2254+
BuildSignature<TM64ResourceName, WBoundary>(builder, typesOnly);
2255+
return true;
2256+
}
2257+
if (features & (NUdf::DateType | NUdf::TzDateType)) {
2258+
BuildSignature<TMResourceName, Boundary>(builder, typesOnly);
2259+
return true;
2260+
}
2261+
2262+
SetInvalidTypeError(builder, typeInfoHelper, argType);
2263+
return true;
2264+
}
2265+
2266+
if (resource.GetTag() == TStringRef::Of(TM64ResourceName)) {
2267+
BuildSignature<TM64ResourceName, WBoundary>(builder, typesOnly);
2268+
return true;
2269+
}
2270+
2271+
if (resource.GetTag() == TStringRef::Of(TMResourceName)) {
2272+
BuildSignature<TMResourceName, Boundary>(builder, typesOnly);
2273+
return true;
2274+
}
2275+
2276+
::TStringBuilder sb;
2277+
sb << "Unexpected Resource tag: got '" << resource.GetTag() << "'";
2278+
builder.SetError(sb);
2279+
return true;
22052280
}
2206-
END_SIMPLE_ARROW_UDF(TEndOf, TStartEndOfBinaryKernelExec<true>::Do);
2281+
private:
2282+
template<auto Func>
2283+
class TImpl : public TBoxedValue {
2284+
public:
2285+
TUnboxedValue Run(const IValueBuilder* valueBuilder, const TUnboxedValuePod* args) const final {
2286+
try {
2287+
return Func(valueBuilder, args);
2288+
} catch (const std::exception&) {
2289+
TStringBuilder sb;
2290+
sb << CurrentExceptionMessage();
2291+
sb << Endl << "[" << TStringBuf(Name()) << "]" ;
2292+
UdfTerminate(sb.c_str());
2293+
}
2294+
}
2295+
};
2296+
2297+
static void SetInvalidTypeError(NUdf::IFunctionTypeInfoBuilder& builder,
2298+
ITypeInfoHelper::TPtr typeInfoHelper, const TType* argType)
2299+
{
2300+
::TStringBuilder sb;
2301+
sb << "Invalid argument type: got ";
2302+
TTypePrinter(*typeInfoHelper, argType).Out(sb.Out);
2303+
sb << ", but Resource<" << TMResourceName <<"> or Resource<"
2304+
<< TM64ResourceName << "> expected";
2305+
builder.SetError(sb);
2306+
}
2307+
2308+
template<const char* TResourceName, auto Func>
2309+
static void BuildSignature(NUdf::IFunctionTypeInfoBuilder& builder, bool typesOnly) {
2310+
builder.Returns<TOptional<TResource<TResourceName>>>();
2311+
builder.Args()->Add<TAutoMap<TResource<TResourceName>>>()
2312+
.template Add<TAutoMap<std::conditional_t<TResourceName == TMResourceName, TInterval, TInterval64>>>();
2313+
builder.IsStrict();
2314+
if (!typesOnly) {
2315+
builder.Implementation(new TImpl<Func>());
2316+
}
2317+
}
2318+
};
22072319

22082320
struct TTimeOfDayKernelExec : TUnaryKernelExec<TTimeOfDayKernelExec, TReaderTraits::TResource<false>, TFixedSizeArrayBuilder<TDataType<TInterval>::TLayout, false>> {
22092321
template<typename TSink>
@@ -2214,13 +2326,126 @@ class TBoundaryOf: public ::NYql::NUdf::TBoxedValue {
22142326
}
22152327
};
22162328

2217-
const auto timeOfDayKernelExecDo = TTimeOfDayKernelExec::Do;
2218-
BEGIN_SIMPLE_STRICT_ARROW_UDF(TTimeOfDay, TInterval(TAutoMap<TResource<TMResourceName>>)) {
2219-
Y_UNUSED(valueBuilder);
2220-
auto& storage = Reference(args[0]);
2221-
return TUnboxedValuePod((i64)storage.ToTimeOfDay());
2329+
class TTimeOfDay: public ::NYql::NUdf::TBoxedValue {
2330+
public:
2331+
typedef bool TTypeAwareMarker;
2332+
static const ::NYql::NUdf::TStringRef& Name() {
2333+
static auto name = TStringRef::Of("TimeOfDay");
2334+
return name;
2335+
}
2336+
2337+
static bool DeclareSignature(
2338+
const ::NYql::NUdf::TStringRef& name,
2339+
::NYql::NUdf::TType* userType,
2340+
::NYql::NUdf::IFunctionTypeInfoBuilder& builder,
2341+
bool typesOnly)
2342+
{
2343+
if (Name() != name) {
2344+
return false;
2345+
}
2346+
2347+
if (!userType) {
2348+
builder.SetError("User type is missing");
2349+
return true;
2350+
}
2351+
2352+
builder.UserType(userType);
2353+
2354+
const auto typeInfoHelper = builder.TypeInfoHelper();
2355+
TTupleTypeInspector tuple(*typeInfoHelper, userType);
2356+
Y_ENSURE(tuple, "Tuple with args and options tuples expected");
2357+
Y_ENSURE(tuple.GetElementsCount() > 0,
2358+
"Tuple has to contain positional arguments");
2359+
2360+
TTupleTypeInspector argsTuple(*typeInfoHelper, tuple.GetElementType(0));
2361+
Y_ENSURE(argsTuple, "Tuple with args expected");
2362+
if (argsTuple.GetElementsCount() != 1) {
2363+
builder.SetError("Single argument expected");
2364+
return true;
2365+
}
2366+
2367+
auto argType = argsTuple.GetElementType(0);
2368+
2369+
if (const auto optType = TOptionalTypeInspector(*typeInfoHelper, argType)) {
2370+
argType = optType.GetItemType();
2371+
}
2372+
2373+
TResourceTypeInspector resource(*typeInfoHelper, argType);
2374+
if (!resource) {
2375+
TDataTypeInspector data(*typeInfoHelper, argType);
2376+
if (!data) {
2377+
SetInvalidTypeError(builder, typeInfoHelper, argType);
2378+
return true;
2379+
}
2380+
2381+
const auto features = NUdf::GetDataTypeInfo(NUdf::GetDataSlot(data.GetTypeId())).Features;
2382+
if (features & NUdf::BigDateType) {
2383+
BuildSignature<TM64ResourceName>(builder, typesOnly);
2384+
return true;
2385+
}
2386+
if (features & (NUdf::DateType | NUdf::TzDateType)) {
2387+
BuildSignature<TMResourceName>(builder, typesOnly);
2388+
return true;
2389+
}
2390+
2391+
SetInvalidTypeError(builder, typeInfoHelper, argType);
2392+
return true;
2393+
}
2394+
2395+
if (resource.GetTag() == TStringRef::Of(TM64ResourceName)) {
2396+
BuildSignature<TM64ResourceName>(builder, typesOnly);
2397+
return true;
2398+
}
2399+
2400+
if (resource.GetTag() == TStringRef::Of(TMResourceName)) {
2401+
BuildSignature<TMResourceName>(builder, typesOnly);
2402+
return true;
2403+
}
2404+
2405+
::TStringBuilder sb;
2406+
sb << "Unexpected Resource tag: got '" << resource.GetTag() << "'";
2407+
builder.SetError(sb);
2408+
return true;
2409+
}
2410+
private:
2411+
template<const char* TResourceName>
2412+
class TImpl : public TBoxedValue {
2413+
public:
2414+
TUnboxedValue Run(const IValueBuilder* valueBuilder, const TUnboxedValuePod* args) const final {
2415+
try {
2416+
Y_UNUSED(valueBuilder);
2417+
auto& storage = Reference<TResourceName>(args[0]);
2418+
return TUnboxedValuePod((i64)storage.ToTimeOfDay());
2419+
} catch (const std::exception&) {
2420+
TStringBuilder sb;
2421+
sb << CurrentExceptionMessage();
2422+
sb << Endl << "[" << TStringBuf(Name()) << "]" ;
2423+
UdfTerminate(sb.c_str());
2424+
}
2425+
}
2426+
};
2427+
2428+
static void SetInvalidTypeError(NUdf::IFunctionTypeInfoBuilder& builder,
2429+
ITypeInfoHelper::TPtr typeInfoHelper, const TType* argType)
2430+
{
2431+
::TStringBuilder sb;
2432+
sb << "Invalid argument type: got ";
2433+
TTypePrinter(*typeInfoHelper, argType).Out(sb.Out);
2434+
sb << ", but Resource<" << TMResourceName <<"> or Resource<"
2435+
<< TM64ResourceName << "> expected";
2436+
builder.SetError(sb);
2437+
}
2438+
2439+
template< const char* TResourceName>
2440+
static void BuildSignature(NUdf::IFunctionTypeInfoBuilder& builder, bool typesOnly) {
2441+
builder.Returns<std::conditional_t<TResourceName == TMResourceName, TInterval, TInterval64>>();
2442+
builder.Args()->Add<TAutoMap<TResource<TResourceName>>>();
2443+
builder.IsStrict();
2444+
if (!typesOnly) {
2445+
builder.Implementation(new TImpl<TResourceName>());
2446+
}
22222447
}
2223-
END_SIMPLE_ARROW_UDF(TTimeOfDay, timeOfDayKernelExecDo);
2448+
};
22242449

22252450

22262451
// Add ...
@@ -3139,7 +3364,8 @@ class TShift : public TBoxedValue {
31393364
SimpleDatetimeToDatetimeUdf<TM64ResourceName, StartOfWeek<TTM64Storage>>>,
31403365
TBoundaryOf<StartOfDayUDF, SimpleDatetimeToDatetimeUdf<TMResourceName, StartOfDay<TTMStorage>>,
31413366
SimpleDatetimeToDatetimeUdf<TM64ResourceName, StartOfDay<TTM64Storage>>>,
3142-
TStartOf,
3367+
TBoundaryOfInterval<StartOfUDF, SimpleDatetimeToIntervalUdf<TMResourceName, StartOf<TTMStorage>>,
3368+
SimpleDatetimeToIntervalUdf<TM64ResourceName, StartOf<TTM64Storage>>>,
31433369
TTimeOfDay,
31443370

31453371
TShift<ShiftYearsUDF, DoAddYears<TMResourceName>, DoAddYears<TM64ResourceName>>,
@@ -3156,7 +3382,8 @@ class TShift : public TBoxedValue {
31563382
SimpleDatetimeToDatetimeUdf<TM64ResourceName, EndOfWeek<TTM64Storage>>>,
31573383
TBoundaryOf<EndOfDayUDF, SimpleDatetimeToDatetimeUdf<TMResourceName, EndOfDay<TTMStorage>>,
31583384
SimpleDatetimeToDatetimeUdf<TM64ResourceName, EndOfDay<TTM64Storage>>>,
3159-
TEndOf,
3385+
TBoundaryOfInterval<EndOfUDF, SimpleDatetimeToIntervalUdf<TMResourceName, EndOf<TTMStorage>>,
3386+
SimpleDatetimeToIntervalUdf<TM64ResourceName, EndOf<TTM64Storage>>>,
31603387

31613388
TToUnits<ToSecondsUDF, ui32, 1>,
31623389
TToUnits<ToMillisecondsUDF, ui64, 1000>,

0 commit comments

Comments
 (0)