datetime_udf.cpp 128 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243
  1. #include <yql/essentials/minikql/mkql_type_ops.h>
  2. #include <yql/essentials/public/udf/tz/udf_tz.h>
  3. #include <yql/essentials/public/udf/udf_helpers.h>
  4. #include <yql/essentials/minikql/datetime/datetime.h>
  5. #include <yql/essentials/minikql/datetime/datetime64.h>
  6. #include <yql/essentials/public/udf/arrow/udf_arrow_helpers.h>
  7. #include <util/datetime/base.h>
  8. using namespace NKikimr;
  9. using namespace NUdf;
  10. using namespace NYql::DateTime;
  11. extern const char SplitUDF[] = "Split";
  12. extern const char ToSecondsUDF[] = "ToSeconds";
  13. extern const char ToMillisecondsUDF[] = "ToMilliseconds";
  14. extern const char ToMicrosecondsUDF[] = "ToMicroseconds";
  15. extern const char GetYearUDF[] = "GetYear";
  16. extern const char GetDayOfYearUDF[] = "GetDayOfYear";
  17. extern const char GetMonthUDF[] = "GetMonth";
  18. extern const char GetMonthNameUDF[] = "GetMonthName";
  19. extern const char GetWeekOfYearUDF[] = "GetWeekOfYear";
  20. extern const char GetWeekOfYearIso8601UDF[] = "GetWeekOfYearIso8601";
  21. extern const char GetDayOfMonthUDF[] = "GetDayOfMonth";
  22. extern const char GetDayOfWeekUDF[] = "GetDayOfWeek";
  23. extern const char GetDayOfWeekNameUDF[] = "GetDayOfWeekName";
  24. extern const char GetTimezoneIdUDF[] = "GetTimezoneId";
  25. extern const char GetTimezoneNameUDF[] = "GetTimezoneName";
  26. extern const char GetHourUDF[] = "GetHour";
  27. extern const char GetMinuteUDF[] = "GetMinute";
  28. extern const char GetSecondUDF[] = "GetSecond";
  29. extern const char GetMillisecondOfSecondUDF[] = "GetMillisecondOfSecond";
  30. extern const char GetMicrosecondOfSecondUDF[] = "GetMicrosecondOfSecond";
  31. extern const char StartOfYearUDF[] = "StartOfYear";
  32. extern const char StartOfQuarterUDF[] = "StartOfQuarter";
  33. extern const char StartOfMonthUDF[] = "StartOfMonth";
  34. extern const char StartOfWeekUDF[] = "StartOfWeek";
  35. extern const char StartOfDayUDF[] = "StartOfDay";
  36. extern const char StartOfUDF[] = "StartOf";
  37. extern const char EndOfYearUDF[] = "EndOfYear";
  38. extern const char EndOfQuarterUDF[] = "EndOfQuarter";
  39. extern const char EndOfMonthUDF[] = "EndOfMonth";
  40. extern const char EndOfWeekUDF[] = "EndOfWeek";
  41. extern const char EndOfDayUDF[] = "EndOfDay";
  42. extern const char EndOfUDF[] = "EndOf";
  43. extern const char ShiftYearsUDF[] = "ShiftYears";
  44. extern const char ShiftQuartersUDF[] = "ShiftQuarters";
  45. extern const char ShiftMonthsUDF[] = "ShiftMonths";
  46. extern const char ParseUDF[] = "Parse";
  47. extern const char Parse64UDF[] = "Parse64";
  48. extern const char TMResourceName[] = "DateTime2.TM";
  49. extern const char TM64ResourceName[] = "DateTime2.TM64";
  50. const auto UsecondsInDay = 86400000000ll;
  51. const auto UsecondsInHour = 3600000000ll;
  52. const auto UsecondsInMinute = 60000000ll;
  53. const auto UsecondsInSecond = 1000000ll;
  54. const auto UsecondsInMilliseconds = 1000ll;
  55. template <const char* TFuncName, typename TResult, ui32 ScaleAfterSeconds>
  56. class TToUnits {
  57. public:
  58. typedef bool TTypeAwareMarker;
  59. using TSignedResult = typename std::make_signed<TResult>::type;
  60. static TResult DateCore(ui16 value) {
  61. return value * ui32(86400) * TResult(ScaleAfterSeconds);
  62. }
  63. template<typename TTzDate>
  64. static TResult TzBlockCore(TBlockItem tzDate);
  65. template<>
  66. static TResult TzBlockCore<TTzDate>(TBlockItem tzDate) {
  67. return DateCore(tzDate.Get<ui16>());
  68. }
  69. template<>
  70. static TResult TzBlockCore<TTzDatetime>(TBlockItem tzDate) {
  71. return DatetimeCore(tzDate.Get<ui32>());
  72. }
  73. template<>
  74. static TResult TzBlockCore<TTzTimestamp>(TBlockItem tzDate) {
  75. return TimestampCore(tzDate.Get<ui64>());
  76. }
  77. static TResult DatetimeCore(ui32 value) {
  78. return value * TResult(ScaleAfterSeconds);
  79. }
  80. static TResult TimestampCore(ui64 value) {
  81. return TResult(value / (1000000u / ScaleAfterSeconds));
  82. }
  83. static TSignedResult IntervalCore(i64 value) {
  84. return TSignedResult(value / (1000000u / ScaleAfterSeconds));
  85. }
  86. static const TStringRef& Name() {
  87. static auto name = TStringRef(TFuncName, std::strlen(TFuncName));
  88. return name;
  89. }
  90. template<typename TTzDate, typename TOutput>
  91. static auto MakeTzBlockExec() {
  92. using TReader = TTzDateBlockReader<TTzDate, /*Nullable*/ false>;
  93. return UnaryPreallocatedReaderExecImpl<TReader, TOutput, TzBlockCore<TTzDate>>;
  94. }
  95. static bool DeclareSignature(
  96. const TStringRef& name,
  97. TType* userType,
  98. IFunctionTypeInfoBuilder& builder,
  99. bool typesOnly)
  100. {
  101. if (Name() != name) {
  102. return false;
  103. }
  104. try {
  105. auto typeInfoHelper = builder.TypeInfoHelper();
  106. TTupleTypeInspector tuple(*typeInfoHelper, userType);
  107. Y_ENSURE(tuple);
  108. Y_ENSURE(tuple.GetElementsCount() > 0);
  109. TTupleTypeInspector argsTuple(*typeInfoHelper, tuple.GetElementType(0));
  110. Y_ENSURE(argsTuple);
  111. if (argsTuple.GetElementsCount() != 1) {
  112. builder.SetError("Expected one argument");
  113. return true;
  114. }
  115. auto argType = argsTuple.GetElementType(0);
  116. TVector<const TType*> argBlockTypes;
  117. argBlockTypes.push_back(argType);
  118. TBlockTypeInspector block(*typeInfoHelper, argType);
  119. if (block) {
  120. Y_ENSURE(!block.IsScalar());
  121. argType = block.GetItemType();
  122. }
  123. bool isOptional = false;
  124. if (auto opt = TOptionalTypeInspector(*typeInfoHelper, argType)) {
  125. argType = opt.GetItemType();
  126. isOptional = true;
  127. }
  128. TDataTypeInspector data(*typeInfoHelper, argType);
  129. if (!data) {
  130. builder.SetError("Expected data type");
  131. return true;
  132. }
  133. auto typeId = data.GetTypeId();
  134. if (!(typeId == TDataType<TDate>::Id || typeId == TDataType<TTzDate>::Id ||
  135. typeId == TDataType<TDatetime>::Id || typeId == TDataType<TTzDatetime>::Id ||
  136. typeId == TDataType<TTimestamp>::Id || typeId == TDataType<TTzTimestamp>::Id ||
  137. typeId == TDataType<TInterval>::Id)) {
  138. builder.SetError(TStringBuilder() << "Type " << GetDataTypeInfo(GetDataSlot(typeId)).Name << " is not supported");
  139. }
  140. builder.Args()->Add(argsTuple.GetElementType(0)).Done();
  141. const TType* retType;
  142. if (typeId != TDataType<TInterval>::Id) {
  143. retType = builder.SimpleType<TResult>();
  144. } else {
  145. retType = builder.SimpleType<TSignedResult>();
  146. }
  147. if (isOptional) {
  148. retType = builder.Optional()->Item(retType).Build();
  149. }
  150. auto outputType = retType;
  151. if (block) {
  152. retType = builder.Block(block.IsScalar())->Item(retType).Build();
  153. }
  154. builder.Returns(retType);
  155. builder.SupportsBlocks();
  156. builder.IsStrict();
  157. builder.UserType(userType);
  158. if (!typesOnly) {
  159. if (typeId == TDataType<TDate>::Id || typeId == TDataType<TTzDate>::Id) {
  160. if (block) {
  161. const auto exec = (typeId == TDataType<TTzDate>::Id)
  162. ? MakeTzBlockExec<TTzDate, TResult>()
  163. : UnaryPreallocatedExecImpl<ui16, TResult, DateCore>;
  164. builder.Implementation(new TSimpleArrowUdfImpl(argBlockTypes, outputType, block.IsScalar(),
  165. exec, builder, TString(name), arrow::compute::NullHandling::INTERSECTION));
  166. } else {
  167. builder.Implementation(new TUnaryOverOptionalImpl<ui16, TResult, DateCore>());
  168. }
  169. }
  170. if (typeId == TDataType<TDatetime>::Id || typeId == TDataType<TTzDatetime>::Id) {
  171. if (block) {
  172. const auto exec = (typeId == TDataType<TTzDatetime>::Id)
  173. ? MakeTzBlockExec<TTzDatetime, TResult>()
  174. : UnaryPreallocatedExecImpl<ui32, TResult, DatetimeCore>;
  175. builder.Implementation(new TSimpleArrowUdfImpl(argBlockTypes, outputType, block.IsScalar(),
  176. exec, builder, TString(name), arrow::compute::NullHandling::INTERSECTION));
  177. } else {
  178. builder.Implementation(new TUnaryOverOptionalImpl<ui32, TResult, DatetimeCore>());
  179. }
  180. }
  181. if (typeId == TDataType<TTimestamp>::Id || typeId == TDataType<TTzTimestamp>::Id) {
  182. if (block) {
  183. const auto exec = (typeId == TDataType<TTzTimestamp>::Id)
  184. ? MakeTzBlockExec<TTzTimestamp, TResult>()
  185. : UnaryPreallocatedExecImpl<ui64, TResult, TimestampCore>;
  186. builder.Implementation(new TSimpleArrowUdfImpl(argBlockTypes, outputType, block.IsScalar(),
  187. exec, builder, TString(name), arrow::compute::NullHandling::INTERSECTION));
  188. } else {
  189. builder.Implementation(new TUnaryOverOptionalImpl<ui64, TResult, TimestampCore>());
  190. }
  191. }
  192. if (typeId == TDataType<TInterval>::Id) {
  193. if (block) {
  194. builder.Implementation(new TSimpleArrowUdfImpl(argBlockTypes, outputType, block.IsScalar(),
  195. UnaryPreallocatedExecImpl<i64, TSignedResult, IntervalCore>, builder, TString(name), arrow::compute::NullHandling::INTERSECTION));
  196. } else {
  197. builder.Implementation(new TUnaryOverOptionalImpl<i64, TSignedResult, IntervalCore>());
  198. }
  199. }
  200. }
  201. } catch (const std::exception& e) {
  202. builder.SetError(TStringBuf(e.what()));
  203. }
  204. return true;
  205. }
  206. };
  207. template <const char* TFuncName, typename TFieldStorage,
  208. TFieldStorage (*Accessor)(const TUnboxedValuePod&),
  209. TFieldStorage (*WAccessor)(const TUnboxedValuePod&),
  210. ui32 Divisor, ui32 Scale, ui32 Limit, bool Fractional>
  211. struct TGetTimeComponent {
  212. typedef bool TTypeAwareMarker;
  213. static const TStringRef& Name() {
  214. static auto name = TStringRef(TFuncName, std::strlen(TFuncName));
  215. return name;
  216. }
  217. static bool DeclareSignature(
  218. const TStringRef& name,
  219. TType* userType,
  220. IFunctionTypeInfoBuilder& builder,
  221. bool typesOnly)
  222. {
  223. if (Name() != name) {
  224. return false;
  225. }
  226. if (!userType) {
  227. builder.SetError("User type is missing");
  228. return true;
  229. }
  230. builder.UserType(userType);
  231. const auto typeInfoHelper = builder.TypeInfoHelper();
  232. TTupleTypeInspector tuple(*typeInfoHelper, userType);
  233. Y_ENSURE(tuple, "Tuple with args and options tuples expected");
  234. Y_ENSURE(tuple.GetElementsCount() > 0,
  235. "Tuple has to contain positional arguments");
  236. TTupleTypeInspector argsTuple(*typeInfoHelper, tuple.GetElementType(0));
  237. Y_ENSURE(argsTuple, "Tuple with args expected");
  238. if (argsTuple.GetElementsCount() != 1) {
  239. builder.SetError("Single argument expected");
  240. return true;
  241. }
  242. auto argType = argsTuple.GetElementType(0);
  243. TVector<const TType*> argBlockTypes;
  244. argBlockTypes.push_back(argType);
  245. TBlockTypeInspector block(*typeInfoHelper, argType);
  246. if (block) {
  247. Y_ENSURE(!block.IsScalar());
  248. argType = block.GetItemType();
  249. }
  250. bool isOptional = false;
  251. if (auto opt = TOptionalTypeInspector(*typeInfoHelper, argType)) {
  252. argType = opt.GetItemType();
  253. isOptional = true;
  254. }
  255. TResourceTypeInspector resource(*typeInfoHelper, argType);
  256. if (!resource) {
  257. TDataTypeInspector data(*typeInfoHelper, argType);
  258. if (!data) {
  259. builder.SetError("Data type expected");
  260. return true;
  261. }
  262. const auto features = NUdf::GetDataTypeInfo(NUdf::GetDataSlot(data.GetTypeId())).Features;
  263. if (features & NUdf::BigDateType) {
  264. BuildSignature<TFieldStorage, TM64ResourceName, WAccessor>(builder, typesOnly);
  265. return true;
  266. }
  267. if (features & NUdf::TzDateType) {
  268. BuildSignature<TFieldStorage, TMResourceName, Accessor>(builder, typesOnly);
  269. return true;
  270. }
  271. if (features & NUdf::DateType) {
  272. builder.Args()->Add(argsTuple.GetElementType(0)).Done();
  273. const TType* retType = builder.SimpleType<TFieldStorage>();
  274. if (isOptional) {
  275. retType = builder.Optional()->Item(retType).Build();
  276. }
  277. auto outputType = retType;
  278. if (block) {
  279. retType = builder.Block(block.IsScalar())->Item(retType).Build();
  280. }
  281. builder.Returns(retType);
  282. builder.SupportsBlocks();
  283. builder.IsStrict();
  284. if (!typesOnly) {
  285. const auto typeId = data.GetTypeId();
  286. if (typeId == TDataType<TDate>::Id) {
  287. if (block) {
  288. builder.Implementation(new TSimpleArrowUdfImpl(argBlockTypes, outputType, block.IsScalar(),
  289. UnaryPreallocatedExecImpl<ui16, TFieldStorage, Core<ui16, true, false>>, builder, TString(name), arrow::compute::NullHandling::INTERSECTION));
  290. } else {
  291. builder.Implementation(new TUnaryOverOptionalImpl<ui16, TFieldStorage, Core<ui16, true, false>>());
  292. }
  293. }
  294. if (typeId == TDataType<TDatetime>::Id) {
  295. if (block) {
  296. builder.Implementation(new TSimpleArrowUdfImpl(argBlockTypes, outputType, block.IsScalar(),
  297. UnaryPreallocatedExecImpl<ui32, TFieldStorage, Core<ui32, false, false>>, builder, TString(name), arrow::compute::NullHandling::INTERSECTION));
  298. } else {
  299. builder.Implementation(new TUnaryOverOptionalImpl<ui32, TFieldStorage, Core<ui32, false, false>>());
  300. }
  301. }
  302. if (typeId == TDataType<TTimestamp>::Id) {
  303. if (block) {
  304. builder.Implementation(new TSimpleArrowUdfImpl(argBlockTypes, outputType, block.IsScalar(),
  305. UnaryPreallocatedExecImpl<ui64, TFieldStorage, Core<ui64, false, true>>, builder, TString(name), arrow::compute::NullHandling::INTERSECTION));
  306. } else {
  307. builder.Implementation(new TUnaryOverOptionalImpl<ui64, TFieldStorage, Core<ui64, false, true>>());
  308. }
  309. }
  310. }
  311. return true;
  312. }
  313. ::TStringBuilder sb;
  314. sb << "Invalid argument type: got ";
  315. TTypePrinter(*typeInfoHelper, argType).Out(sb.Out);
  316. sb << ", but Resource<" << TMResourceName <<"> or Resource<"
  317. << TM64ResourceName << "> expected";
  318. builder.SetError(sb);
  319. return true;
  320. }
  321. Y_ENSURE(!block);
  322. if (resource.GetTag() == TStringRef::Of(TM64ResourceName)) {
  323. BuildSignature<TFieldStorage, TM64ResourceName, WAccessor>(builder, typesOnly);
  324. return true;
  325. }
  326. if (resource.GetTag() == TStringRef::Of(TMResourceName)) {
  327. BuildSignature<TFieldStorage, TMResourceName, Accessor>(builder, typesOnly);
  328. return true;
  329. }
  330. builder.SetError("Unexpected Resource tag");
  331. return true;
  332. }
  333. private:
  334. template <typename TInput, bool AlwaysZero, bool InputFractional>
  335. static TFieldStorage Core(TInput val) {
  336. if constexpr (AlwaysZero) {
  337. return 0;
  338. }
  339. if constexpr (InputFractional) {
  340. if constexpr (Fractional) {
  341. return (val / Scale) % Limit;
  342. } else {
  343. return (val / 1000000u / Scale) % Limit;
  344. }
  345. } else {
  346. if constexpr (Fractional) {
  347. return 0;
  348. } else {
  349. return (val / Scale) % Limit;
  350. }
  351. }
  352. }
  353. template<typename TResult, TResult (*Func)(const TUnboxedValuePod&)>
  354. class TImpl : public TBoxedValue {
  355. public:
  356. TUnboxedValue Run(const IValueBuilder* valueBuilder, const TUnboxedValuePod* args) const final {
  357. Y_UNUSED(valueBuilder);
  358. EMPTY_RESULT_ON_EMPTY_ARG(0);
  359. return TUnboxedValuePod((TResult(Func(args[0])) / Divisor));
  360. }
  361. };
  362. template<typename TResult, const char* TResourceName, TResult (*Func)(const TUnboxedValuePod&)>
  363. static void BuildSignature(NUdf::IFunctionTypeInfoBuilder& builder, bool typesOnly) {
  364. builder.Returns<TResult>();
  365. builder.Args()->Add<TAutoMap<TResource<TResourceName>>>();
  366. builder.IsStrict();
  367. if (!typesOnly) {
  368. builder.Implementation(new TImpl<TResult, Func>());
  369. }
  370. }
  371. };
  372. namespace {
  373. // FIXME: The default value for TResourceName allows to omit
  374. // explicit specialization in functions that still doesn't support
  375. // big datetime types. Should be removed in future.
  376. template<const char* TResourceName = TMResourceName, typename TValue,
  377. typename TStorage = std::conditional_t<TResourceName == TMResourceName,
  378. TTMStorage, TTM64Storage>>
  379. const TStorage& Reference(const TValue& value) {
  380. return *reinterpret_cast<const TStorage*>(value.GetRawPtr());
  381. }
  382. // FIXME: The default value for TResourceName allows to omit
  383. // explicit specialization in functions that still doesn't support
  384. // big datetime types. Should be removed in future.
  385. template<const char* TResourceName = TMResourceName, typename TValue,
  386. typename TStorage = std::conditional_t<TResourceName == TMResourceName,
  387. TTMStorage, TTM64Storage>>
  388. TStorage& Reference(TValue& value) {
  389. return *reinterpret_cast<TStorage*>(value.GetRawPtr());
  390. }
  391. template<const char* TResourceName>
  392. TUnboxedValuePod DoAddMonths(const TUnboxedValuePod& date, i64 months, const NUdf::IDateBuilder& builder) {
  393. auto result = date;
  394. auto& storage = Reference<TResourceName>(result);
  395. if (!NYql::DateTime::DoAddMonths(storage, months, builder)) {
  396. return TUnboxedValuePod{};
  397. }
  398. return result;
  399. }
  400. template<const char* TResourceName>
  401. TUnboxedValuePod DoAddQuarters(const TUnboxedValuePod& date, i64 quarters, const NUdf::IDateBuilder& builder) {
  402. return DoAddMonths<TResourceName>(date, quarters * 3ll, builder);
  403. }
  404. template<const char* TResourceName>
  405. TUnboxedValuePod DoAddYears(const TUnboxedValuePod& date, i64 years, const NUdf::IDateBuilder& builder) {
  406. auto result = date;
  407. auto& storage = Reference<TResourceName>(result);
  408. if (!NYql::DateTime::DoAddYears(storage, years, builder)) {
  409. return TUnboxedValuePod{};
  410. }
  411. return result;
  412. }
  413. // FIXME: The default value for TResourceName allows to omit
  414. // explicit specialization in functions that still doesn't support
  415. // big datetime types. Should be removed in future.
  416. #define ACCESSORS_POLY(field, type, wtype) \
  417. template<const char* TResourceName = TMResourceName, typename TValue, \
  418. typename rtype = std::conditional_t<TResourceName == TMResourceName, \
  419. type, wtype>> \
  420. inline rtype Get##field(const TValue& tm) { \
  421. return (rtype)Reference<TResourceName>(tm).field; \
  422. } \
  423. template<const char* TResourceName = TMResourceName, typename TValue, \
  424. typename itype = std::conditional_t<TResourceName == TMResourceName, \
  425. type, wtype>> \
  426. inline void Set##field(TValue& tm, itype value) { \
  427. Reference<TResourceName>(tm).field = value; \
  428. } \
  429. #define ACCESSORS(field, type) \
  430. ACCESSORS_POLY(field, type, type)
  431. ACCESSORS_POLY(Year, ui16, i32)
  432. ACCESSORS(DayOfYear, ui16)
  433. ACCESSORS(WeekOfYear, ui8)
  434. ACCESSORS(WeekOfYearIso8601, ui8)
  435. ACCESSORS(DayOfWeek, ui8)
  436. ACCESSORS(Month, ui8)
  437. ACCESSORS(Day, ui8)
  438. ACCESSORS(Hour, ui8)
  439. ACCESSORS(Minute, ui8)
  440. ACCESSORS(Second, ui8)
  441. ACCESSORS(Microsecond, ui32)
  442. ACCESSORS(TimezoneId, ui16)
  443. #undef ACCESSORS
  444. #undef ACCESSORS_POLY
  445. // FIXME: The default value for TResourceName allows to omit
  446. // explicit specialization in functions that still doesn't support
  447. // big datetime types. Should be removed in future.
  448. template<const char* TResourceName = TMResourceName>
  449. inline bool ValidateYear(std::conditional_t<TResourceName == TMResourceName, ui16, i32> year) {
  450. if constexpr (TResourceName == TMResourceName) {
  451. return year >= NUdf::MIN_YEAR || year < NUdf::MAX_YEAR;
  452. } else {
  453. return year >= NUdf::MIN_YEAR32 || year < NUdf::MAX_YEAR32;
  454. }
  455. }
  456. inline bool ValidateMonth(ui8 month) {
  457. return month >= 1 && month <= 12;
  458. }
  459. inline bool ValidateDay(ui8 day) {
  460. return day >= 1 && day <= 31;
  461. }
  462. inline bool ValidateHour(ui8 hour) {
  463. return hour < 24;
  464. }
  465. inline bool ValidateMinute(ui8 minute) {
  466. return minute < 60;
  467. }
  468. inline bool ValidateSecond(ui8 second) {
  469. return second < 60;
  470. }
  471. inline bool ValidateMicrosecond(ui32 microsecond) {
  472. return microsecond < 1000000;
  473. }
  474. inline bool ValidateTimezoneId(ui16 timezoneId) {
  475. const auto& zones = NUdf::GetTimezones();
  476. return timezoneId < zones.size() && !zones[timezoneId].empty();
  477. }
  478. inline bool ValidateMonthShortName(const std::string_view& monthName, ui8& month) {
  479. static constexpr auto cmp = [](const std::string_view& a, const std::string_view& b) {
  480. int cmp = strnicmp(a.data(), b.data(), std::min(a.size(), b.size()));
  481. if (cmp == 0)
  482. return a.size() < b.size();
  483. return cmp < 0;
  484. };
  485. static const std::map<std::string_view, ui8, decltype(cmp)> mp = {
  486. {"jan", 1},
  487. {"feb", 2},
  488. {"mar", 3},
  489. {"apr", 4},
  490. {"may", 5},
  491. {"jun", 6},
  492. {"jul", 7},
  493. {"aug", 8},
  494. {"sep", 9},
  495. {"oct", 10},
  496. {"nov", 11},
  497. {"dec", 12}
  498. };
  499. const auto& it = mp.find(monthName);
  500. if (it != mp.end()) {
  501. month = it -> second;
  502. return true;
  503. }
  504. return false;
  505. }
  506. inline bool ValidateMonthFullName(const std::string_view& monthName, ui8& month) {
  507. static constexpr auto cmp = [](const std::string_view& a, const std::string_view& b) {
  508. int cmp = strnicmp(a.data(), b.data(), std::min(a.size(), b.size()));
  509. if (cmp == 0)
  510. return a.size() < b.size();
  511. return cmp < 0;
  512. };
  513. static const std::map<std::string_view, ui8, decltype(cmp)> mp = {
  514. {"january", 1},
  515. {"february", 2},
  516. {"march", 3},
  517. {"april", 4},
  518. {"may", 5},
  519. {"june", 6},
  520. {"july", 7},
  521. {"august", 8},
  522. {"september", 9},
  523. {"october", 10},
  524. {"november", 11},
  525. {"december", 12}
  526. };
  527. const auto& it = mp.find(monthName);
  528. if (it != mp.end()) {
  529. month = it -> second;
  530. return true;
  531. }
  532. return false;
  533. }
  534. template<typename TType>
  535. inline bool Validate(typename TDataType<TType>::TLayout arg);
  536. template<>
  537. inline bool Validate<TTimestamp>(ui64 timestamp) {
  538. return timestamp < MAX_TIMESTAMP;
  539. }
  540. template<>
  541. inline bool Validate<TTimestamp64>(i64 timestamp) {
  542. return timestamp >= MIN_TIMESTAMP64 && timestamp <= MAX_TIMESTAMP64;
  543. }
  544. template<>
  545. inline bool Validate<TInterval>(i64 interval) {
  546. return interval > -i64(MAX_TIMESTAMP) && interval < i64(MAX_TIMESTAMP);
  547. }
  548. template<>
  549. inline bool Validate<TInterval64>(i64 interval) {
  550. return interval >= -MAX_INTERVAL64 && interval <= MAX_INTERVAL64;
  551. }
  552. // Split
  553. template<typename TUserDataType, bool Nullable>
  554. using TSplitArgReader = std::conditional_t<TTzDataType<TUserDataType>::Result,
  555. TTzDateBlockReader<TUserDataType, Nullable>,
  556. TFixedSizeBlockReader<typename TDataType<TUserDataType>::TLayout, Nullable>>;
  557. template<typename TUserDataType>
  558. struct TSplitKernelExec : TUnaryKernelExec<TSplitKernelExec<TUserDataType>, TSplitArgReader<TUserDataType, false>, TResourceArrayBuilder<false>> {
  559. static void Split(TBlockItem arg, TTMStorage& storage, const IValueBuilder& valueBuilder);
  560. template<typename TSink>
  561. static void Process(const IValueBuilder* valueBuilder, TBlockItem arg, const TSink& sink) {
  562. try {
  563. TBlockItem res {0};
  564. Split(arg, Reference(res), *valueBuilder);
  565. sink(res);
  566. } catch (const std::exception& e) {
  567. UdfTerminate((TStringBuilder() << e.what()).data());
  568. }
  569. }
  570. };
  571. template <typename TUserDataType>
  572. class TSplit : public TBoxedValue {
  573. const TSourcePosition Pos_;
  574. public:
  575. explicit TSplit(TSourcePosition pos)
  576. : Pos_(pos)
  577. {}
  578. TUnboxedValue Run(
  579. const IValueBuilder* valueBuilder,
  580. const TUnboxedValuePod* args) const override;
  581. static bool DeclareSignature(
  582. TStringRef name,
  583. TType* userType,
  584. IFunctionTypeInfoBuilder& builder,
  585. bool typesOnly)
  586. {
  587. const auto typeInfoHelper = builder.TypeInfoHelper();
  588. TTupleTypeInspector tuple(*typeInfoHelper, userType);
  589. Y_ENSURE(tuple);
  590. Y_ENSURE(tuple.GetElementsCount() > 0);
  591. TTupleTypeInspector argsTuple(*typeInfoHelper, tuple.GetElementType(0));
  592. Y_ENSURE(argsTuple);
  593. if (argsTuple.GetElementsCount() != 1) {
  594. builder.SetError("Expected one argument");
  595. return true;
  596. }
  597. auto argType = argsTuple.GetElementType(0);
  598. builder.UserType(userType);
  599. builder.SupportsBlocks();
  600. builder.IsStrict();
  601. TBlockTypeInspector block(*typeInfoHelper, argType);
  602. if (block) {
  603. const auto* blockArgType = builder.Block(false)->Item<TUserDataType>().Build();
  604. builder.Args()->Add(blockArgType).Flags(ICallablePayload::TArgumentFlags::AutoMap);
  605. const auto* retType = builder.Resource(TMResourceName);
  606. const auto* blockRetType = builder.Block(false)->Item(retType).Build();
  607. builder.Returns(blockRetType);
  608. if (!typesOnly) {
  609. builder.Implementation(new TSimpleArrowUdfImpl({blockArgType}, retType, block.IsScalar(),
  610. TSplitKernelExec<TUserDataType>::Do, builder, TString(name), arrow::compute::NullHandling::COMPUTED_NO_PREALLOCATE));
  611. }
  612. } else {
  613. builder.Args()->Add<TUserDataType>().Flags(ICallablePayload::TArgumentFlags::AutoMap);
  614. if constexpr (NUdf::TDataType<TUserDataType>::Features & NYql::NUdf::BigDateType) {
  615. builder.Returns(builder.Resource(TM64ResourceName));
  616. } else {
  617. builder.Returns(builder.Resource(TMResourceName));
  618. }
  619. if (!typesOnly) {
  620. builder.Implementation(new TSplit<TUserDataType>(builder.GetSourcePosition()));
  621. }
  622. }
  623. return true;
  624. }
  625. };
  626. template <>
  627. void TSplitKernelExec<TDate>::Split(TBlockItem arg, TTMStorage &storage, const IValueBuilder& builder) {
  628. storage.FromDate(builder.GetDateBuilder(), arg.Get<ui16>());
  629. }
  630. template <>
  631. void TSplitKernelExec<TDatetime>::Split(TBlockItem arg, TTMStorage &storage, const IValueBuilder& builder) {
  632. storage.FromDatetime(builder.GetDateBuilder(), arg.Get<ui32>());
  633. }
  634. template <>
  635. void TSplitKernelExec<TTimestamp>::Split(TBlockItem arg, TTMStorage &storage, const IValueBuilder& builder) {
  636. storage.FromTimestamp(builder.GetDateBuilder(), arg.Get<ui64>());
  637. }
  638. template <>
  639. void TSplitKernelExec<TTzDate>::Split(TBlockItem arg, TTMStorage &storage, const IValueBuilder& builder) {
  640. storage.FromDate(builder.GetDateBuilder(), arg.Get<ui16>(), arg.GetTimezoneId());
  641. }
  642. template <>
  643. void TSplitKernelExec<TTzDatetime>::Split(TBlockItem arg, TTMStorage &storage, const IValueBuilder& builder) {
  644. storage.FromDatetime(builder.GetDateBuilder(), arg.Get<ui32>(), arg.GetTimezoneId());
  645. }
  646. template <>
  647. void TSplitKernelExec<TTzTimestamp>::Split(TBlockItem arg, TTMStorage &storage, const IValueBuilder& builder) {
  648. storage.FromTimestamp(builder.GetDateBuilder(), arg.Get<ui64>(), arg.GetTimezoneId());
  649. }
  650. template <>
  651. void TSplitKernelExec<TDate32>::Split(TBlockItem, TTMStorage&, const IValueBuilder&) {
  652. ythrow yexception() << "Not implemented";
  653. }
  654. template <>
  655. void TSplitKernelExec<TDatetime64>::Split(TBlockItem, TTMStorage&, const IValueBuilder&) {
  656. ythrow yexception() << "Not implemented";
  657. }
  658. template <>
  659. void TSplitKernelExec<TTimestamp64>::Split(TBlockItem, TTMStorage&, const IValueBuilder&) {
  660. ythrow yexception() << "Not implemented";
  661. }
  662. template <>
  663. TUnboxedValue TSplit<TDate>::Run(
  664. const IValueBuilder* valueBuilder,
  665. const TUnboxedValuePod* args) const
  666. {
  667. try {
  668. EMPTY_RESULT_ON_EMPTY_ARG(0);
  669. auto& builder = valueBuilder->GetDateBuilder();
  670. TUnboxedValuePod result(0);
  671. auto& storage = Reference(result);
  672. storage.FromDate(builder, args[0].Get<ui16>());
  673. return result;
  674. } catch (const std::exception& e) {
  675. UdfTerminate((TStringBuilder() << Pos_ << " " << e.what()).data());
  676. }
  677. }
  678. template <>
  679. TUnboxedValue TSplit<TDate32>::Run(
  680. const IValueBuilder* valueBuilder,
  681. const TUnboxedValuePod* args) const
  682. {
  683. try {
  684. EMPTY_RESULT_ON_EMPTY_ARG(0);
  685. TUnboxedValuePod result(0);
  686. auto& storage = Reference<TM64ResourceName>(result);
  687. storage.FromDate32(valueBuilder->GetDateBuilder(), args[0].Get<i32>());
  688. return result;
  689. } catch (const std::exception& e) {
  690. UdfTerminate((TStringBuilder() << Pos_ << " " << e.what()).data());
  691. }
  692. }
  693. template <>
  694. TUnboxedValue TSplit<TDatetime>::Run(
  695. const IValueBuilder* valueBuilder,
  696. const TUnboxedValuePod* args) const
  697. {
  698. try {
  699. EMPTY_RESULT_ON_EMPTY_ARG(0);
  700. auto& builder = valueBuilder->GetDateBuilder();
  701. TUnboxedValuePod result(0);
  702. auto& storage = Reference(result);
  703. storage.FromDatetime(builder, args[0].Get<ui32>());
  704. return result;
  705. } catch (const std::exception& e) {
  706. UdfTerminate((TStringBuilder() << Pos_ << " " << e.what()).data());
  707. }
  708. }
  709. template <>
  710. TUnboxedValue TSplit<TDatetime64>::Run(
  711. const IValueBuilder* valueBuilder,
  712. const TUnboxedValuePod* args) const
  713. {
  714. try {
  715. EMPTY_RESULT_ON_EMPTY_ARG(0);
  716. TUnboxedValuePod result(0);
  717. auto& storage = Reference<TM64ResourceName>(result);
  718. storage.FromDatetime64(valueBuilder->GetDateBuilder(), args[0].Get<i64>());
  719. return result;
  720. } catch (const std::exception& e) {
  721. UdfTerminate((TStringBuilder() << Pos_ << " " << e.what()).data());
  722. }
  723. }
  724. template <>
  725. TUnboxedValue TSplit<TTimestamp>::Run(
  726. const IValueBuilder* valueBuilder,
  727. const TUnboxedValuePod* args) const
  728. {
  729. try {
  730. EMPTY_RESULT_ON_EMPTY_ARG(0);
  731. auto& builder = valueBuilder->GetDateBuilder();
  732. TUnboxedValuePod result(0);
  733. auto& storage = Reference(result);
  734. storage.FromTimestamp(builder, args[0].Get<ui64>());
  735. return result;
  736. } catch (const std::exception& e) {
  737. UdfTerminate((TStringBuilder() << Pos_ << " " << e.what()).data());
  738. }
  739. }
  740. template <>
  741. TUnboxedValue TSplit<TTimestamp64>::Run(
  742. const IValueBuilder* valueBuilder,
  743. const TUnboxedValuePod* args) const
  744. {
  745. try {
  746. EMPTY_RESULT_ON_EMPTY_ARG(0);
  747. TUnboxedValuePod result(0);
  748. auto& storage = Reference<TM64ResourceName>(result);
  749. storage.FromTimestamp64(valueBuilder->GetDateBuilder(), args[0].Get<i64>());
  750. return result;
  751. } catch (const std::exception& e) {
  752. UdfTerminate((TStringBuilder() << Pos_ << " " << e.what()).data());
  753. }
  754. }
  755. template <>
  756. TUnboxedValue TSplit<TTzDate>::Run(
  757. const IValueBuilder* valueBuilder,
  758. const TUnboxedValuePod* args) const
  759. {
  760. try {
  761. EMPTY_RESULT_ON_EMPTY_ARG(0);
  762. auto& builder = valueBuilder->GetDateBuilder();
  763. TUnboxedValuePod result(0);
  764. auto& storage = Reference(result);
  765. storage.FromDate(builder, args[0].Get<ui16>(), args[0].GetTimezoneId());
  766. return result;
  767. } catch (const std::exception& e) {
  768. UdfTerminate((TStringBuilder() << Pos_ << " " << e.what()).data());
  769. }
  770. }
  771. template <>
  772. TUnboxedValue TSplit<TTzDatetime>::Run(
  773. const IValueBuilder* valueBuilder,
  774. const TUnboxedValuePod* args) const
  775. {
  776. try {
  777. EMPTY_RESULT_ON_EMPTY_ARG(0);
  778. auto& builder = valueBuilder->GetDateBuilder();
  779. TUnboxedValuePod result(0);
  780. auto& storage = Reference(result);
  781. storage.FromDatetime(builder, args[0].Get<ui32>(), args[0].GetTimezoneId());
  782. return result;
  783. } catch (const std::exception& e) {
  784. UdfTerminate((TStringBuilder() << Pos_ << " " << e.what()).data());
  785. }
  786. }
  787. template <>
  788. TUnboxedValue TSplit<TTzTimestamp>::Run(
  789. const IValueBuilder* valueBuilder,
  790. const TUnboxedValuePod* args) const
  791. {
  792. try {
  793. EMPTY_RESULT_ON_EMPTY_ARG(0);
  794. auto& builder = valueBuilder->GetDateBuilder();
  795. TUnboxedValuePod result(0);
  796. auto& storage = Reference(result);
  797. storage.FromTimestamp(builder, args[0].Get<ui64>(), args[0].GetTimezoneId());
  798. return result;
  799. } catch (const std::exception& e) {
  800. UdfTerminate((TStringBuilder() << Pos_ << " " << e.what()).data());
  801. }
  802. }
  803. // Make*
  804. template<typename TUserDataType, bool Nullable>
  805. using TMakeResBuilder = std::conditional_t<TTzDataType<TUserDataType>::Result,
  806. TTzDateArrayBuilder<TUserDataType, Nullable>,
  807. TFixedSizeArrayBuilder<typename TDataType<TUserDataType>::TLayout, Nullable>>;
  808. template<typename TUserDataType>
  809. struct TMakeDateKernelExec : TUnaryKernelExec<TMakeDateKernelExec<TUserDataType>, TReaderTraits::TResource<false>, TMakeResBuilder<TUserDataType, false>> {
  810. static TBlockItem Make(TTMStorage& storage, const IValueBuilder& valueBuilder);
  811. template<typename TSink>
  812. static void Process(const IValueBuilder* valueBuilder, TBlockItem item, const TSink& sink) {
  813. auto& storage = Reference(item);
  814. sink(TBlockItem(Make(storage, *valueBuilder)));
  815. }
  816. };
  817. template<> TBlockItem TMakeDateKernelExec<TDate>::Make(TTMStorage& storage, const IValueBuilder& valueBuilder) {
  818. TBlockItem res(storage.ToDate(valueBuilder.GetDateBuilder(), /*local*/ false));
  819. return res;
  820. }
  821. template<> TBlockItem TMakeDateKernelExec<TDatetime>::Make(TTMStorage& storage, const IValueBuilder& valueBuilder) {
  822. TBlockItem res(storage.ToDatetime(valueBuilder.GetDateBuilder()));
  823. return res;
  824. }
  825. template<> TBlockItem TMakeDateKernelExec<TTimestamp>::Make(TTMStorage& storage, const IValueBuilder& valueBuilder) {
  826. TBlockItem res(storage.ToTimestamp(valueBuilder.GetDateBuilder()));
  827. return res;
  828. }
  829. template<> TBlockItem TMakeDateKernelExec<TTzDate>::Make(TTMStorage& storage, const IValueBuilder& valueBuilder) {
  830. TBlockItem res(storage.ToDate(valueBuilder.GetDateBuilder(), /*local*/ true));
  831. res.SetTimezoneId(storage.TimezoneId);
  832. return res;
  833. }
  834. template<> TBlockItem TMakeDateKernelExec<TTzDatetime>::Make(TTMStorage& storage, const IValueBuilder& valueBuilder) {
  835. TBlockItem res(storage.ToDatetime(valueBuilder.GetDateBuilder()));
  836. res.SetTimezoneId(storage.TimezoneId);
  837. return res;
  838. }
  839. template<> TBlockItem TMakeDateKernelExec<TTzTimestamp>::Make(TTMStorage& storage, const IValueBuilder& valueBuilder) {
  840. TBlockItem res(storage.ToTimestamp(valueBuilder.GetDateBuilder()));
  841. res.SetTimezoneId(storage.TimezoneId);
  842. return res;
  843. }
  844. BEGIN_SIMPLE_STRICT_ARROW_UDF(TMakeDate, TDate(TAutoMap<TResource<TMResourceName>>)) {
  845. auto& builder = valueBuilder->GetDateBuilder();
  846. auto& storage = Reference(args[0]);
  847. return TUnboxedValuePod(storage.ToDate(builder, false));
  848. }
  849. END_SIMPLE_ARROW_UDF(TMakeDate, TMakeDateKernelExec<TDate>::Do);
  850. BEGIN_SIMPLE_STRICT_ARROW_UDF(TMakeDatetime, TDatetime(TAutoMap<TResource<TMResourceName>>)) {
  851. auto& builder = valueBuilder->GetDateBuilder();
  852. auto& storage = Reference(args[0]);
  853. return TUnboxedValuePod(storage.ToDatetime(builder));
  854. }
  855. END_SIMPLE_ARROW_UDF(TMakeDatetime, TMakeDateKernelExec<TDatetime>::Do);
  856. BEGIN_SIMPLE_STRICT_ARROW_UDF(TMakeTimestamp, TTimestamp(TAutoMap<TResource<TMResourceName>>)) {
  857. auto& builder = valueBuilder->GetDateBuilder();
  858. auto& storage = Reference(args[0]);
  859. return TUnboxedValuePod(storage.ToTimestamp(builder));
  860. }
  861. END_SIMPLE_ARROW_UDF(TMakeTimestamp, TMakeDateKernelExec<TTimestamp>::Do);
  862. BEGIN_SIMPLE_STRICT_ARROW_UDF(TMakeTzDate, TTzDate(TAutoMap<TResource<TMResourceName>>)) {
  863. auto& builder = valueBuilder->GetDateBuilder();
  864. auto& storage = Reference(args[0]);
  865. try {
  866. TUnboxedValuePod result(storage.ToDate(builder, true));
  867. result.SetTimezoneId(storage.TimezoneId);
  868. return result;
  869. } catch (const std::exception& e) {
  870. UdfTerminate((TStringBuilder() << Pos_ << "Timestamp "
  871. << storage.ToString()
  872. << " cannot be casted to TzDate"
  873. ).data());
  874. }
  875. }
  876. END_SIMPLE_ARROW_UDF(TMakeTzDate, TMakeDateKernelExec<TTzDate>::Do);
  877. BEGIN_SIMPLE_STRICT_ARROW_UDF(TMakeTzDatetime, TTzDatetime(TAutoMap<TResource<TMResourceName>>)) {
  878. auto& builder = valueBuilder->GetDateBuilder();
  879. auto& storage = Reference(args[0]);
  880. TUnboxedValuePod result(storage.ToDatetime(builder));
  881. result.SetTimezoneId(storage.TimezoneId);
  882. return result;
  883. }
  884. END_SIMPLE_ARROW_UDF(TMakeTzDatetime, TMakeDateKernelExec<TTzDatetime>::Do);
  885. BEGIN_SIMPLE_STRICT_ARROW_UDF(TMakeTzTimestamp, TTzTimestamp(TAutoMap<TResource<TMResourceName>>)) {
  886. auto& builder = valueBuilder->GetDateBuilder();
  887. auto& storage = Reference(args[0]);
  888. TUnboxedValuePod result(storage.ToTimestamp(builder));
  889. result.SetTimezoneId(storage.TimezoneId);
  890. return result;
  891. }
  892. END_SIMPLE_ARROW_UDF(TMakeTzTimestamp, TMakeDateKernelExec<TTzTimestamp>::Do);
  893. SIMPLE_STRICT_UDF(TConvert, TResource<TM64ResourceName>(TAutoMap<TResource<TMResourceName>>)) {
  894. Y_UNUSED(valueBuilder);
  895. TUnboxedValuePod result(0);
  896. auto& arg = Reference(args[0]);
  897. auto& storage = Reference<TM64ResourceName>(result);
  898. storage.From(arg);
  899. return result;
  900. }
  901. SIMPLE_STRICT_UDF(TMakeDate32, TDate32(TAutoMap<TResource<TM64ResourceName>>)) {
  902. auto& storage = Reference<TM64ResourceName>(args[0]);
  903. return TUnboxedValuePod(storage.ToDate32(valueBuilder->GetDateBuilder()));
  904. }
  905. SIMPLE_STRICT_UDF(TMakeDatetime64, TDatetime64(TAutoMap<TResource<TM64ResourceName>>)) {
  906. auto& storage = Reference<TM64ResourceName>(args[0]);
  907. return TUnboxedValuePod(storage.ToDatetime64(valueBuilder->GetDateBuilder()));
  908. }
  909. SIMPLE_STRICT_UDF(TMakeTimestamp64, TTimestamp64(TAutoMap<TResource<TM64ResourceName>>)) {
  910. auto& storage = Reference<TM64ResourceName>(args[0]);
  911. return TUnboxedValuePod(storage.ToTimestamp64(valueBuilder->GetDateBuilder()));
  912. }
  913. // Get*
  914. // #define GET_METHOD(field, type) \
  915. // struct TGet##field##KernelExec : TUnaryKernelExec<TGet##field##KernelExec, TReaderTraits::TResource<false>, TFixedSizeArrayBuilder<type, false>> { \
  916. // template<typename TSink> \
  917. // static void Process(TBlockItem item, const IValueBuilder& valueBuilder, const TSink& sink) { \
  918. // Y_UNUSED(valueBuilder); \
  919. // sink(TBlockItem(Get##field(item))); \
  920. // } \
  921. // }; \
  922. // BEGIN_SIMPLE_STRICT_ARROW_UDF(TGet##field, type(TAutoMap<TResource<TMResourceName>>)) { \
  923. // Y_UNUSED(valueBuilder); \
  924. // return TUnboxedValuePod(Get##field(args[0])); \
  925. // } \
  926. // END_SIMPLE_ARROW_UDF_WITH_NULL_HANDLING(TGet##field, TGet##field##KernelExec::Do, arrow::compute::NullHandling::INTERSECTION);
  927. template<const char* TUdfName,
  928. typename TResultType, TResultType (*Accessor)(const TUnboxedValuePod&),
  929. typename TResultWType, TResultWType (*WAccessor)(const TUnboxedValuePod&)>
  930. class TGetDateComponent: public ::NYql::NUdf::TBoxedValue {
  931. public:
  932. typedef bool TTypeAwareMarker;
  933. static const ::NYql::NUdf::TStringRef& Name() {
  934. static auto name = TStringRef(TUdfName, std::strlen(TUdfName));
  935. return name;
  936. }
  937. static bool DeclareSignature(
  938. const ::NYql::NUdf::TStringRef& name,
  939. ::NYql::NUdf::TType* userType,
  940. ::NYql::NUdf::IFunctionTypeInfoBuilder& builder,
  941. bool typesOnly)
  942. {
  943. if (Name() != name) {
  944. return false;
  945. }
  946. if (!userType) {
  947. builder.SetError("User type is missing");
  948. return true;
  949. }
  950. builder.UserType(userType);
  951. const auto typeInfoHelper = builder.TypeInfoHelper();
  952. TTupleTypeInspector tuple(*typeInfoHelper, userType);
  953. Y_ENSURE(tuple, "Tuple with args and options tuples expected");
  954. Y_ENSURE(tuple.GetElementsCount() > 0,
  955. "Tuple has to contain positional arguments");
  956. TTupleTypeInspector argsTuple(*typeInfoHelper, tuple.GetElementType(0));
  957. Y_ENSURE(argsTuple, "Tuple with args expected");
  958. if (argsTuple.GetElementsCount() != 1) {
  959. builder.SetError("Single argument expected");
  960. return true;
  961. }
  962. auto argType = argsTuple.GetElementType(0);
  963. if (const auto optType = TOptionalTypeInspector(*typeInfoHelper, argType)) {
  964. argType = optType.GetItemType();
  965. }
  966. TResourceTypeInspector resource(*typeInfoHelper, argType);
  967. if (!resource) {
  968. TDataTypeInspector data(*typeInfoHelper, argType);
  969. if (!data) {
  970. builder.SetError("Data type expected");
  971. return true;
  972. }
  973. const auto features = NUdf::GetDataTypeInfo(NUdf::GetDataSlot(data.GetTypeId())).Features;
  974. if (features & NUdf::BigDateType) {
  975. BuildSignature<TResultWType, TM64ResourceName, WAccessor>(builder, typesOnly);
  976. return true;
  977. }
  978. if (features & (NUdf::DateType | NUdf::TzDateType)) {
  979. BuildSignature<TResultType, TMResourceName, Accessor>(builder, typesOnly);
  980. return true;
  981. }
  982. ::TStringBuilder sb;
  983. sb << "Invalid argument type: got ";
  984. TTypePrinter(*typeInfoHelper, argType).Out(sb.Out);
  985. sb << ", but Resource<" << TMResourceName <<"> or Resource<"
  986. << TM64ResourceName << "> expected";
  987. builder.SetError(sb);
  988. return true;
  989. }
  990. if (resource.GetTag() == TStringRef::Of(TM64ResourceName)) {
  991. BuildSignature<TResultWType, TM64ResourceName, WAccessor>(builder, typesOnly);
  992. return true;
  993. }
  994. if (resource.GetTag() == TStringRef::Of(TMResourceName)) {
  995. BuildSignature<TResultType, TMResourceName, Accessor>(builder, typesOnly);
  996. return true;
  997. }
  998. builder.SetError("Unexpected Resource tag");
  999. return true;
  1000. }
  1001. private:
  1002. template<typename TResult, TResult (*Func)(const TUnboxedValuePod&)>
  1003. class TImpl : public TBoxedValue {
  1004. public:
  1005. TUnboxedValue Run(const IValueBuilder* valueBuilder, const TUnboxedValuePod* args) const final {
  1006. Y_UNUSED(valueBuilder);
  1007. EMPTY_RESULT_ON_EMPTY_ARG(0);
  1008. return TUnboxedValuePod(TResult(Func(args[0])));
  1009. }
  1010. };
  1011. template<typename TResult, const char* TResourceName, TResult (*Func)(const TUnboxedValuePod&)>
  1012. static void BuildSignature(NUdf::IFunctionTypeInfoBuilder& builder, bool typesOnly) {
  1013. builder.Returns<TResult>();
  1014. builder.Args()->Add<TAutoMap<TResource<TResourceName>>>();
  1015. builder.IsStrict();
  1016. if (!typesOnly) {
  1017. builder.Implementation(new TImpl<TResult, Func>());
  1018. }
  1019. }
  1020. };
  1021. // TODO: Merge this with <TGetDateComponent> class.
  1022. template<const char* TUdfName, auto Accessor, auto WAccessor>
  1023. class TGetDateComponentName: public ::NYql::NUdf::TBoxedValue {
  1024. public:
  1025. typedef bool TTypeAwareMarker;
  1026. static const ::NYql::NUdf::TStringRef& Name() {
  1027. static auto name = TStringRef(TUdfName, std::strlen(TUdfName));
  1028. return name;
  1029. }
  1030. static bool DeclareSignature(
  1031. const ::NYql::NUdf::TStringRef& name,
  1032. ::NYql::NUdf::TType* userType,
  1033. ::NYql::NUdf::IFunctionTypeInfoBuilder& builder,
  1034. bool typesOnly)
  1035. {
  1036. if (Name() != name) {
  1037. return false;
  1038. }
  1039. if (!userType) {
  1040. builder.SetError("User type is missing");
  1041. return true;
  1042. }
  1043. builder.UserType(userType);
  1044. const auto typeInfoHelper = builder.TypeInfoHelper();
  1045. TTupleTypeInspector tuple(*typeInfoHelper, userType);
  1046. Y_ENSURE(tuple, "Tuple with args and options tuples expected");
  1047. Y_ENSURE(tuple.GetElementsCount() > 0,
  1048. "Tuple has to contain positional arguments");
  1049. TTupleTypeInspector argsTuple(*typeInfoHelper, tuple.GetElementType(0));
  1050. Y_ENSURE(argsTuple, "Tuple with args expected");
  1051. if (argsTuple.GetElementsCount() != 1) {
  1052. builder.SetError("Single argument expected");
  1053. return true;
  1054. }
  1055. auto argType = argsTuple.GetElementType(0);
  1056. if (const auto optType = TOptionalTypeInspector(*typeInfoHelper, argType)) {
  1057. argType = optType.GetItemType();
  1058. }
  1059. TResourceTypeInspector resource(*typeInfoHelper, argType);
  1060. if (!resource) {
  1061. TDataTypeInspector data(*typeInfoHelper, argType);
  1062. if (!data) {
  1063. builder.SetError("Data type expected");
  1064. return true;
  1065. }
  1066. const auto features = NUdf::GetDataTypeInfo(NUdf::GetDataSlot(data.GetTypeId())).Features;
  1067. if (features & NUdf::BigDateType) {
  1068. BuildSignature<TM64ResourceName, WAccessor>(builder, typesOnly);
  1069. return true;
  1070. }
  1071. if (features & (NUdf::DateType | NUdf::TzDateType)) {
  1072. BuildSignature<TMResourceName, Accessor>(builder, typesOnly);
  1073. return true;
  1074. }
  1075. ::TStringBuilder sb;
  1076. sb << "Invalid argument type: got ";
  1077. TTypePrinter(*typeInfoHelper, argType).Out(sb.Out);
  1078. sb << ", but Resource<" << TMResourceName <<"> or Resource<"
  1079. << TM64ResourceName << "> expected";
  1080. builder.SetError(sb);
  1081. return true;
  1082. }
  1083. if (resource.GetTag() == TStringRef::Of(TM64ResourceName)) {
  1084. BuildSignature<TM64ResourceName, WAccessor>(builder, typesOnly);
  1085. return true;
  1086. }
  1087. if (resource.GetTag() == TStringRef::Of(TMResourceName)) {
  1088. BuildSignature<TMResourceName, Accessor>(builder, typesOnly);
  1089. return true;
  1090. }
  1091. builder.SetError("Unexpected Resource tag");
  1092. return true;
  1093. }
  1094. private:
  1095. template<auto Func>
  1096. class TImpl : public TBoxedValue {
  1097. public:
  1098. TUnboxedValue Run(const IValueBuilder* valueBuilder, const TUnboxedValuePod* args) const final {
  1099. EMPTY_RESULT_ON_EMPTY_ARG(0);
  1100. return Func(valueBuilder, args[0]);
  1101. }
  1102. };
  1103. template<const char* TResourceName, auto Func>
  1104. static void BuildSignature(NUdf::IFunctionTypeInfoBuilder& builder, bool typesOnly) {
  1105. builder.Returns<char*>();
  1106. builder.Args()->Add<TAutoMap<TResource<TResourceName>>>();
  1107. builder.IsStrict();
  1108. if (!typesOnly) {
  1109. builder.Implementation(new TImpl<Func>());
  1110. }
  1111. }
  1112. };
  1113. // template<typename TValue>
  1114. // TValue GetMonthNameValue(size_t idx) {
  1115. // static const std::array<TValue, 12U> monthNames = {{
  1116. // TValue::Embedded(TStringRef::Of("January")),
  1117. // TValue::Embedded(TStringRef::Of("February")),
  1118. // TValue::Embedded(TStringRef::Of("March")),
  1119. // TValue::Embedded(TStringRef::Of("April")),
  1120. // TValue::Embedded(TStringRef::Of("May")),
  1121. // TValue::Embedded(TStringRef::Of("June")),
  1122. // TValue::Embedded(TStringRef::Of("July")),
  1123. // TValue::Embedded(TStringRef::Of("August")),
  1124. // TValue::Embedded(TStringRef::Of("September")),
  1125. // TValue::Embedded(TStringRef::Of("October")),
  1126. // TValue::Embedded(TStringRef::Of("November")),
  1127. // TValue::Embedded(TStringRef::Of("December"))
  1128. // }};
  1129. // return monthNames.at(idx);
  1130. // }
  1131. // struct TGetMonthNameKernelExec : TUnaryKernelExec<TGetMonthNameKernelExec, TReaderTraits::TResource<true>, TStringArrayBuilder<arrow::StringType, false>> {
  1132. // template<typename TSink>
  1133. // static void Process(const IValueBuilder* valueBuilder, TBlockItem item, const TSink& sink) {
  1134. // Y_UNUSED(valueBuilder);
  1135. // sink(GetMonthNameValue<TBlockItem>(GetMonth(item) - 1U));
  1136. // }
  1137. // };
  1138. // BEGIN_SIMPLE_STRICT_ARROW_UDF(TGetMonthName, char*(TAutoMap<TResource<TMResourceName>>)) {
  1139. // Y_UNUSED(valueBuilder);
  1140. // return GetMonthNameValue<TUnboxedValue>(GetMonth(*args) - 1U);
  1141. // }
  1142. // END_SIMPLE_ARROW_UDF_WITH_NULL_HANDLING(TGetMonthName, TGetMonthNameKernelExec::Do, arrow::compute::NullHandling::INTERSECTION);
  1143. template<const char* TResourceName>
  1144. TUnboxedValue GetMonthName(const IValueBuilder* valueBuilder, const TUnboxedValuePod& arg) {
  1145. Y_UNUSED(valueBuilder);
  1146. static const std::array<TUnboxedValue, 12U> monthNames = {{
  1147. TUnboxedValuePod::Embedded(TStringRef::Of("January")),
  1148. TUnboxedValuePod::Embedded(TStringRef::Of("February")),
  1149. TUnboxedValuePod::Embedded(TStringRef::Of("March")),
  1150. TUnboxedValuePod::Embedded(TStringRef::Of("April")),
  1151. TUnboxedValuePod::Embedded(TStringRef::Of("May")),
  1152. TUnboxedValuePod::Embedded(TStringRef::Of("June")),
  1153. TUnboxedValuePod::Embedded(TStringRef::Of("July")),
  1154. TUnboxedValuePod::Embedded(TStringRef::Of("August")),
  1155. TUnboxedValuePod::Embedded(TStringRef::Of("September")),
  1156. TUnboxedValuePod::Embedded(TStringRef::Of("October")),
  1157. TUnboxedValuePod::Embedded(TStringRef::Of("November")),
  1158. TUnboxedValuePod::Embedded(TStringRef::Of("December"))
  1159. }};
  1160. return monthNames.at(GetMonth<TResourceName>(arg) - 1U);
  1161. }
  1162. // struct TGetDayOfMonthKernelExec : TUnaryKernelExec<TGetMonthNameKernelExec, TReaderTraits::TResource<false>, TFixedSizeArrayBuilder<ui8, false>> {
  1163. // template<typename TSink>
  1164. // static void Process(TBlockItem item, const TSink& sink) {
  1165. // sink(GetDay(item));
  1166. // }
  1167. // };
  1168. // BEGIN_SIMPLE_STRICT_ARROW_UDF(TGetDayOfMonth, ui8(TAutoMap<TResource<TMResourceName>>)) {
  1169. // Y_UNUSED(valueBuilder);
  1170. // return TUnboxedValuePod(GetDay(args[0]));
  1171. // }
  1172. // END_SIMPLE_ARROW_UDF_WITH_NULL_HANDLING(TGetDayOfMonth, TGetDayOfMonthKernelExec::Do, arrow::compute::NullHandling::INTERSECTION);
  1173. template<const char* TResourceName>
  1174. TUnboxedValue GetDayOfWeekName(const IValueBuilder* valueBuilder, const TUnboxedValuePod& arg) {
  1175. Y_UNUSED(valueBuilder);
  1176. static const std::array<TUnboxedValue, 7U> dayNames = {{
  1177. TUnboxedValuePod::Embedded(TStringRef::Of("Monday")),
  1178. TUnboxedValuePod::Embedded(TStringRef::Of("Tuesday")),
  1179. TUnboxedValuePod::Embedded(TStringRef::Of("Wednesday")),
  1180. TUnboxedValuePod::Embedded(TStringRef::Of("Thursday")),
  1181. TUnboxedValuePod::Embedded(TStringRef::Of("Friday")),
  1182. TUnboxedValuePod::Embedded(TStringRef::Of("Saturday")),
  1183. TUnboxedValuePod::Embedded(TStringRef::Of("Sunday"))
  1184. }};
  1185. return dayNames.at(GetDayOfWeek<TResourceName>(arg) - 1U);
  1186. }
  1187. // struct TGetDayOfWeekNameKernelExec : TUnaryKernelExec<TGetDayOfWeekNameKernelExec, TReaderTraits::TResource<true>, TStringArrayBuilder<arrow::StringType, false>> {
  1188. // template<typename TSink>
  1189. // static void Process(const IValueBuilder* valueBuilder, TBlockItem item, const TSink& sink) {
  1190. // Y_UNUSED(valueBuilder);
  1191. // sink(GetDayNameValue<TBlockItem>(GetDayOfWeek(item) - 1U));
  1192. // }
  1193. // };
  1194. // BEGIN_SIMPLE_STRICT_ARROW_UDF(TGetDayOfWeekName, char*(TAutoMap<TResource<TMResourceName>>)) {
  1195. // Y_UNUSED(valueBuilder);
  1196. // return GetDayNameValue<TUnboxedValuePod>(GetDayOfWeek(*args) - 1U);
  1197. // }
  1198. // END_SIMPLE_ARROW_UDF_WITH_NULL_HANDLING(TGetDayOfWeekName, TGetDayOfWeekNameKernelExec::Do, arrow::compute::NullHandling::INTERSECTION);
  1199. struct TTGetTimezoneNameKernelExec : TUnaryKernelExec<TTGetTimezoneNameKernelExec, TReaderTraits::TResource<false>, TStringArrayBuilder<arrow::BinaryType, false>> {
  1200. template<typename TSink>
  1201. static void Process(const IValueBuilder* valueBuilder, TBlockItem item, const TSink& sink) {
  1202. Y_UNUSED(valueBuilder);
  1203. auto timezoneId = GetTimezoneId(item);
  1204. if (timezoneId >= NUdf::GetTimezones().size()) {
  1205. sink(TBlockItem{});
  1206. } else {
  1207. sink(TBlockItem{NUdf::GetTimezones()[timezoneId]});
  1208. }
  1209. }
  1210. };
  1211. BEGIN_SIMPLE_STRICT_ARROW_UDF(TGetTimezoneName, char*(TAutoMap<TResource<TMResourceName>>)) {
  1212. auto timezoneId = GetTimezoneId(args[0]);
  1213. if (timezoneId >= NUdf::GetTimezones().size()) {
  1214. return TUnboxedValuePod();
  1215. }
  1216. return valueBuilder->NewString(NUdf::GetTimezones()[timezoneId]);
  1217. }
  1218. END_SIMPLE_ARROW_UDF(TGetTimezoneName, TTGetTimezoneNameKernelExec::Do);
  1219. template<const char* TResourceName>
  1220. TUnboxedValue GetTimezoneName(const IValueBuilder* valueBuilder, const TUnboxedValuePod& arg) {
  1221. const ui16 tzId = GetTimezoneId<TResourceName>(arg);
  1222. const auto& tzNames = NUdf::GetTimezones();
  1223. if (tzId >= tzNames.size()) {
  1224. return TUnboxedValuePod();
  1225. }
  1226. return valueBuilder->NewString(tzNames[tzId]);
  1227. }
  1228. // Update
  1229. class TUpdate : public TBoxedValue {
  1230. public:
  1231. typedef bool TTypeAwareMarker;
  1232. static const TStringRef& Name() {
  1233. static auto name = TStringRef::Of("Update");
  1234. return name;
  1235. }
  1236. static bool DeclareSignature(
  1237. const TStringRef& name,
  1238. TType* userType,
  1239. IFunctionTypeInfoBuilder& builder,
  1240. bool typesOnly)
  1241. {
  1242. if (Name() != name) {
  1243. return false;
  1244. }
  1245. if (!userType) {
  1246. builder.SetError("User type is missing");
  1247. return true;
  1248. }
  1249. builder.UserType(userType);
  1250. const auto typeInfoHelper = builder.TypeInfoHelper();
  1251. TTupleTypeInspector tuple(*typeInfoHelper, userType);
  1252. Y_ENSURE(tuple, "Tuple with args and options tuples expected");
  1253. Y_ENSURE(tuple.GetElementsCount() > 0,
  1254. "Tuple has to contain positional arguments");
  1255. TTupleTypeInspector argsTuple(*typeInfoHelper, tuple.GetElementType(0));
  1256. Y_ENSURE(argsTuple, "Tuple with args expected");
  1257. if (argsTuple.GetElementsCount() == 0) {
  1258. builder.SetError("At least one argument expected");
  1259. return true;
  1260. }
  1261. auto argType = argsTuple.GetElementType(0);
  1262. if (const auto optType = TOptionalTypeInspector(*typeInfoHelper, argType)) {
  1263. argType = optType.GetItemType();
  1264. }
  1265. TResourceTypeInspector resource(*typeInfoHelper, argType);
  1266. if (!resource) {
  1267. TDataTypeInspector data(*typeInfoHelper, argType);
  1268. if (!data) {
  1269. SetInvalidTypeError(builder, typeInfoHelper, argType);
  1270. return true;
  1271. }
  1272. const auto features = NUdf::GetDataTypeInfo(NUdf::GetDataSlot(data.GetTypeId())).Features;
  1273. if (features & NUdf::BigDateType) {
  1274. BuildSignature<TM64ResourceName>(builder, typesOnly);
  1275. return true;
  1276. }
  1277. if (features & (NUdf::DateType | NUdf::TzDateType)) {
  1278. BuildSignature<TMResourceName>(builder, typesOnly);
  1279. return true;
  1280. }
  1281. SetInvalidTypeError(builder, typeInfoHelper, argType);
  1282. return true;
  1283. }
  1284. if (resource.GetTag() == TStringRef::Of(TM64ResourceName)) {
  1285. BuildSignature<TM64ResourceName>(builder, typesOnly);
  1286. return true;
  1287. }
  1288. if (resource.GetTag() == TStringRef::Of(TMResourceName)) {
  1289. BuildSignature<TMResourceName>(builder, typesOnly);
  1290. return true;
  1291. }
  1292. ::TStringBuilder sb;
  1293. sb << "Unexpected Resource tag: got '" << resource.GetTag() << "'";
  1294. builder.SetError(sb);
  1295. return true;
  1296. }
  1297. private:
  1298. template<const char* TResourceName>
  1299. class TImpl : public TBoxedValue {
  1300. public:
  1301. TUnboxedValue Run(const IValueBuilder* valueBuilder, const TUnboxedValuePod* args) const final {
  1302. try {
  1303. EMPTY_RESULT_ON_EMPTY_ARG(0);
  1304. auto result = args[0];
  1305. if (args[1]) {
  1306. auto year = args[1].Get<std::conditional_t<TResourceName == TMResourceName, ui16, i32>>();
  1307. if (!ValidateYear<TResourceName>(year)) {
  1308. return TUnboxedValuePod();
  1309. }
  1310. SetYear<TResourceName>(result, year);
  1311. }
  1312. if (args[2]) {
  1313. auto month = args[2].Get<ui8>();
  1314. if (!ValidateMonth(month)) {
  1315. return TUnboxedValuePod();
  1316. }
  1317. SetMonth<TResourceName>(result, month);
  1318. }
  1319. if (args[3]) {
  1320. auto day = args[3].Get<ui8>();
  1321. if (!ValidateDay(day)) {
  1322. return TUnboxedValuePod();
  1323. }
  1324. SetDay<TResourceName>(result, day);
  1325. }
  1326. if (args[4]) {
  1327. auto hour = args[4].Get<ui8>();
  1328. if (!ValidateHour(hour)) {
  1329. return TUnboxedValuePod();
  1330. }
  1331. SetHour<TResourceName>(result, hour);
  1332. }
  1333. if (args[5]) {
  1334. auto minute = args[5].Get<ui8>();
  1335. if (!ValidateMinute(minute)) {
  1336. return TUnboxedValuePod();
  1337. }
  1338. SetMinute<TResourceName>(result, minute);
  1339. }
  1340. if (args[6]) {
  1341. auto second = args[6].Get<ui8>();
  1342. if (!ValidateSecond(second)) {
  1343. return TUnboxedValuePod();
  1344. }
  1345. SetSecond<TResourceName>(result, second);
  1346. }
  1347. if (args[7]) {
  1348. auto microsecond = args[7].Get<ui32>();
  1349. if (!ValidateMicrosecond(microsecond)) {
  1350. return TUnboxedValuePod();
  1351. }
  1352. SetMicrosecond<TResourceName>(result, microsecond);
  1353. }
  1354. if (args[8]) {
  1355. auto timezoneId = args[8].Get<ui16>();
  1356. if (!ValidateTimezoneId(timezoneId)) {
  1357. return TUnboxedValuePod();
  1358. }
  1359. SetTimezoneId<TResourceName>(result, timezoneId);
  1360. }
  1361. auto& builder = valueBuilder->GetDateBuilder();
  1362. auto& storage = Reference<TResourceName>(result);
  1363. if (!storage.Validate(builder)) {
  1364. return TUnboxedValuePod();
  1365. }
  1366. return result;
  1367. } catch (const std::exception& e) {
  1368. TStringBuilder sb;
  1369. sb << CurrentExceptionMessage();
  1370. sb << Endl << "[" << TStringBuf(Name()) << "]" ;
  1371. UdfTerminate(sb.c_str());
  1372. }
  1373. }
  1374. };
  1375. static void SetInvalidTypeError(NUdf::IFunctionTypeInfoBuilder& builder,
  1376. ITypeInfoHelper::TPtr typeInfoHelper, const TType* argType)
  1377. {
  1378. ::TStringBuilder sb;
  1379. sb << "Invalid argument type: got ";
  1380. TTypePrinter(*typeInfoHelper, argType).Out(sb.Out);
  1381. sb << ", but Resource<" << TMResourceName <<"> or Resource<"
  1382. << TM64ResourceName << "> expected";
  1383. builder.SetError(sb);
  1384. }
  1385. template<const char* TResourceName>
  1386. static void BuildSignature(NUdf::IFunctionTypeInfoBuilder& builder, bool typesOnly) {
  1387. builder.Returns<TOptional<TResource<TResourceName>>>();
  1388. builder.OptionalArgs(8).Args()->Add<TAutoMap<TResource<TResourceName>>>()
  1389. .template Add<TOptional<std::conditional_t<TResourceName == TMResourceName, ui16, i32>>>().Name("Year")
  1390. .template Add<TOptional<ui8>>().Name("Month")
  1391. .template Add<TOptional<ui8>>().Name("Day")
  1392. .template Add<TOptional<ui8>>().Name("Hour")
  1393. .template Add<TOptional<ui8>>().Name("Minute")
  1394. .template Add<TOptional<ui8>>().Name("Second")
  1395. .template Add<TOptional<ui32>>().Name("Microsecond")
  1396. .template Add<TOptional<ui16>>().Name("TimezoneId");
  1397. builder.IsStrict();
  1398. if (!typesOnly) {
  1399. builder.Implementation(new TImpl<TResourceName>());
  1400. }
  1401. }
  1402. };
  1403. // From*
  1404. template<typename TInput, typename TOutput, i64 UsecMultiplier>
  1405. inline TUnboxedValuePod TFromConverter(TInput arg) {
  1406. using TLayout = TDataType<TOutput>::TLayout;
  1407. const TLayout usec = TLayout(arg) * UsecMultiplier;
  1408. return Validate<TOutput>(usec) ? TUnboxedValuePod(usec) : TUnboxedValuePod();
  1409. }
  1410. template<typename TInput, typename TOutput, i64 UsecMultiplier>
  1411. using TFromConverterKernel = TUnaryUnsafeFixedSizeFilterKernel<TInput,
  1412. typename TDataType<TOutput>::TLayout, [] (TInput arg) {
  1413. using TLayout = TDataType<TOutput>::TLayout;
  1414. const TLayout usec = TLayout(arg) * UsecMultiplier;
  1415. return std::make_pair(usec, Validate<TOutput>(usec));
  1416. }>;
  1417. #define DATETIME_FROM_CONVERTER_UDF(name, retType, argType, usecMultiplier) \
  1418. BEGIN_SIMPLE_STRICT_ARROW_UDF(T##name, TOptional<retType>(TAutoMap<argType>)) { \
  1419. Y_UNUSED(valueBuilder); \
  1420. return TFromConverter<argType, retType, usecMultiplier>(args[0].Get<argType>()); \
  1421. } \
  1422. \
  1423. END_SIMPLE_ARROW_UDF(T##name, (TFromConverterKernel<argType, retType, usecMultiplier>::Do))
  1424. DATETIME_FROM_CONVERTER_UDF(FromSeconds, TTimestamp, ui32, UsecondsInSecond);
  1425. DATETIME_FROM_CONVERTER_UDF(FromMilliseconds, TTimestamp, ui64, UsecondsInMilliseconds);
  1426. DATETIME_FROM_CONVERTER_UDF(FromMicroseconds, TTimestamp, ui64, 1);
  1427. DATETIME_FROM_CONVERTER_UDF(FromSeconds64, TTimestamp64, i64, UsecondsInSecond);
  1428. DATETIME_FROM_CONVERTER_UDF(FromMilliseconds64, TTimestamp64, i64, UsecondsInMilliseconds);
  1429. DATETIME_FROM_CONVERTER_UDF(FromMicroseconds64, TTimestamp64, i64, 1);
  1430. DATETIME_FROM_CONVERTER_UDF(IntervalFromDays, TInterval, i32, UsecondsInDay);
  1431. DATETIME_FROM_CONVERTER_UDF(IntervalFromHours, TInterval, i32, UsecondsInHour);
  1432. DATETIME_FROM_CONVERTER_UDF(IntervalFromMinutes, TInterval, i32, UsecondsInMinute);
  1433. DATETIME_FROM_CONVERTER_UDF(IntervalFromSeconds, TInterval, i32, UsecondsInSecond);
  1434. DATETIME_FROM_CONVERTER_UDF(IntervalFromMilliseconds, TInterval, i64, UsecondsInMilliseconds);
  1435. DATETIME_FROM_CONVERTER_UDF(IntervalFromMicroseconds, TInterval, i64, 1);
  1436. DATETIME_FROM_CONVERTER_UDF(Interval64FromDays, TInterval64, i32, UsecondsInDay);
  1437. DATETIME_FROM_CONVERTER_UDF(Interval64FromHours, TInterval64, i64, UsecondsInHour);
  1438. DATETIME_FROM_CONVERTER_UDF(Interval64FromMinutes, TInterval64, i64, UsecondsInMinute);
  1439. DATETIME_FROM_CONVERTER_UDF(Interval64FromSeconds, TInterval64, i64, UsecondsInSecond);
  1440. DATETIME_FROM_CONVERTER_UDF(Interval64FromMilliseconds, TInterval64, i64, UsecondsInMilliseconds);
  1441. DATETIME_FROM_CONVERTER_UDF(Interval64FromMicroseconds, TInterval64, i64, 1);
  1442. // To*
  1443. BEGIN_SIMPLE_STRICT_ARROW_UDF(TToDays, i32(TAutoMap<TInterval>)) {
  1444. Y_UNUSED(valueBuilder);
  1445. return TUnboxedValuePod(i32(args[0].Get<i64>() / UsecondsInDay));
  1446. }
  1447. END_SIMPLE_ARROW_UDF_WITH_NULL_HANDLING(TToDays,
  1448. (UnaryPreallocatedExecImpl<i64, i32, [] (i64 arg) { return i32(arg / UsecondsInDay); }>),
  1449. arrow::compute::NullHandling::INTERSECTION);
  1450. BEGIN_SIMPLE_STRICT_ARROW_UDF(TToHours, i32(TAutoMap<TInterval>)) {
  1451. Y_UNUSED(valueBuilder);
  1452. return TUnboxedValuePod(i32(args[0].Get<i64>() / UsecondsInHour));
  1453. }
  1454. END_SIMPLE_ARROW_UDF_WITH_NULL_HANDLING(TToHours,
  1455. (UnaryPreallocatedExecImpl<i64, i32, [] (i64 arg) { return i32(arg / UsecondsInHour); }>),
  1456. arrow::compute::NullHandling::INTERSECTION);
  1457. BEGIN_SIMPLE_STRICT_ARROW_UDF(TToMinutes, i32(TAutoMap<TInterval>)) {
  1458. Y_UNUSED(valueBuilder);
  1459. return TUnboxedValuePod(i32(args[0].Get<i64>() / UsecondsInMinute));
  1460. }
  1461. END_SIMPLE_ARROW_UDF_WITH_NULL_HANDLING(TToMinutes,
  1462. (UnaryPreallocatedExecImpl<i64, i32, [] (i64 arg) { return i32(arg / UsecondsInMinute); }>),
  1463. arrow::compute::NullHandling::INTERSECTION);
  1464. // StartOf*
  1465. template<auto Core>
  1466. struct TStartOfKernelExec : TUnaryKernelExec<TStartOfKernelExec<Core>, TResourceBlockReader<false>, TResourceArrayBuilder<true>> {
  1467. template<typename TSink>
  1468. static void Process(const IValueBuilder* valueBuilder, TBlockItem item, const TSink& sink) {
  1469. if (auto res = Core(Reference(item), *valueBuilder)) {
  1470. Reference(item) = res.GetRef();
  1471. sink(item);
  1472. } else {
  1473. sink(TBlockItem{});
  1474. }
  1475. }
  1476. };
  1477. template<const char* TResourceName, auto Core>
  1478. TUnboxedValue SimpleDatetimeToDatetimeUdf(const IValueBuilder* valueBuilder, const TUnboxedValuePod* args) {
  1479. auto result = args[0];
  1480. auto& storage = Reference<TResourceName>(result);
  1481. if (auto res = Core(storage, *valueBuilder)) {
  1482. storage = res.GetRef();
  1483. return result;
  1484. }
  1485. return TUnboxedValuePod{};
  1486. }
  1487. template<const char* TUdfName, auto Boundary, auto WBoundary>
  1488. class TBoundaryOf: public ::NYql::NUdf::TBoxedValue {
  1489. public:
  1490. typedef bool TTypeAwareMarker;
  1491. static const ::NYql::NUdf::TStringRef& Name() {
  1492. static auto name = TStringRef(TUdfName, std::strlen(TUdfName));
  1493. return name;
  1494. }
  1495. static bool DeclareSignature(
  1496. const ::NYql::NUdf::TStringRef& name,
  1497. ::NYql::NUdf::TType* userType,
  1498. ::NYql::NUdf::IFunctionTypeInfoBuilder& builder,
  1499. bool typesOnly)
  1500. {
  1501. if (Name() != name) {
  1502. return false;
  1503. }
  1504. if (!userType) {
  1505. builder.SetError("User type is missing");
  1506. return true;
  1507. }
  1508. builder.UserType(userType);
  1509. const auto typeInfoHelper = builder.TypeInfoHelper();
  1510. TTupleTypeInspector tuple(*typeInfoHelper, userType);
  1511. Y_ENSURE(tuple, "Tuple with args and options tuples expected");
  1512. Y_ENSURE(tuple.GetElementsCount() > 0,
  1513. "Tuple has to contain positional arguments");
  1514. TTupleTypeInspector argsTuple(*typeInfoHelper, tuple.GetElementType(0));
  1515. Y_ENSURE(argsTuple, "Tuple with args expected");
  1516. if (argsTuple.GetElementsCount() != 1) {
  1517. builder.SetError("Single argument expected");
  1518. return true;
  1519. }
  1520. auto argType = argsTuple.GetElementType(0);
  1521. if (const auto optType = TOptionalTypeInspector(*typeInfoHelper, argType)) {
  1522. argType = optType.GetItemType();
  1523. }
  1524. TResourceTypeInspector resource(*typeInfoHelper, argType);
  1525. if (!resource) {
  1526. TDataTypeInspector data(*typeInfoHelper, argType);
  1527. if (!data) {
  1528. SetInvalidTypeError(builder, typeInfoHelper, argType);
  1529. return true;
  1530. }
  1531. const auto features = NUdf::GetDataTypeInfo(NUdf::GetDataSlot(data.GetTypeId())).Features;
  1532. if (features & NUdf::BigDateType) {
  1533. BuildSignature<TM64ResourceName, WBoundary>(builder, typesOnly);
  1534. return true;
  1535. }
  1536. if (features & (NUdf::DateType | NUdf::TzDateType)) {
  1537. BuildSignature<TMResourceName, Boundary>(builder, typesOnly);
  1538. return true;
  1539. }
  1540. SetInvalidTypeError(builder, typeInfoHelper, argType);
  1541. return true;
  1542. }
  1543. if (resource.GetTag() == TStringRef::Of(TM64ResourceName)) {
  1544. BuildSignature<TM64ResourceName, WBoundary>(builder, typesOnly);
  1545. return true;
  1546. }
  1547. if (resource.GetTag() == TStringRef::Of(TMResourceName)) {
  1548. BuildSignature<TMResourceName, Boundary>(builder, typesOnly);
  1549. return true;
  1550. }
  1551. ::TStringBuilder sb;
  1552. sb << "Unexpected Resource tag: got '" << resource.GetTag() << "'";
  1553. builder.SetError(sb);
  1554. return true;
  1555. }
  1556. private:
  1557. template<auto Func>
  1558. class TImpl : public TBoxedValue {
  1559. public:
  1560. TUnboxedValue Run(const IValueBuilder* valueBuilder, const TUnboxedValuePod* args) const final {
  1561. try {
  1562. return Func(valueBuilder, args);
  1563. } catch (const std::exception&) {
  1564. TStringBuilder sb;
  1565. sb << CurrentExceptionMessage();
  1566. sb << Endl << "[" << TStringBuf(Name()) << "]" ;
  1567. UdfTerminate(sb.c_str());
  1568. }
  1569. }
  1570. };
  1571. static void SetInvalidTypeError(NUdf::IFunctionTypeInfoBuilder& builder,
  1572. ITypeInfoHelper::TPtr typeInfoHelper, const TType* argType)
  1573. {
  1574. ::TStringBuilder sb;
  1575. sb << "Invalid argument type: got ";
  1576. TTypePrinter(*typeInfoHelper, argType).Out(sb.Out);
  1577. sb << ", but Resource<" << TMResourceName <<"> or Resource<"
  1578. << TM64ResourceName << "> expected";
  1579. builder.SetError(sb);
  1580. }
  1581. template< const char* TResourceName, auto Func>
  1582. static void BuildSignature(NUdf::IFunctionTypeInfoBuilder& builder, bool typesOnly) {
  1583. builder.Returns<TOptional<TResource<TResourceName>>>();
  1584. builder.Args()->Add<TAutoMap<TResource<TResourceName>>>();
  1585. builder.IsStrict();
  1586. if (!typesOnly) {
  1587. builder.Implementation(new TImpl<Func>());
  1588. }
  1589. }
  1590. };
  1591. template<typename TStorage>
  1592. void SetStartOfDay(TStorage& storage) {
  1593. storage.Hour = 0;
  1594. storage.Minute = 0;
  1595. storage.Second = 0;
  1596. storage.Microsecond = 0;
  1597. }
  1598. template<typename TStorage>
  1599. void SetEndOfDay(TStorage& storage) {
  1600. storage.Hour = 23;
  1601. storage.Minute = 59;
  1602. storage.Second = 59;
  1603. storage.Microsecond = 999999;
  1604. }
  1605. template<typename TStorage>
  1606. TMaybe<TStorage> StartOfYear(TStorage storage, const IValueBuilder& valueBuilder) {
  1607. storage.Month = 1;
  1608. storage.Day = 1;
  1609. SetStartOfDay(storage);
  1610. if (!storage.Validate(valueBuilder.GetDateBuilder())) {
  1611. return {};
  1612. }
  1613. return storage;
  1614. }
  1615. template<typename TStorage>
  1616. TMaybe<TStorage> EndOfYear(TStorage storage, const IValueBuilder& valueBuilder) {
  1617. storage.Month = 12;
  1618. storage.Day = 31;
  1619. SetEndOfDay(storage);
  1620. if (!storage.Validate(valueBuilder.GetDateBuilder())) {
  1621. return {};
  1622. }
  1623. return storage;
  1624. }
  1625. template<typename TStorage>
  1626. TMaybe<TStorage> StartOfQuarter(TStorage storage, const IValueBuilder& valueBuilder) {
  1627. storage.Month = (storage.Month - 1) / 3 * 3 + 1;
  1628. storage.Day = 1;
  1629. SetStartOfDay(storage);
  1630. if (!storage.Validate(valueBuilder.GetDateBuilder())) {
  1631. return {};
  1632. }
  1633. return storage;
  1634. }
  1635. template<typename TStorage>
  1636. TMaybe<TStorage> EndOfQuarter(TStorage storage, const IValueBuilder& valueBuilder) {
  1637. storage.Month = ((storage.Month - 1) / 3 + 1) * 3;
  1638. storage.Day = NMiniKQL::GetMonthLength(storage.Month, NMiniKQL::IsLeapYear(storage.Year));
  1639. SetEndOfDay(storage);
  1640. if (!storage.Validate(valueBuilder.GetDateBuilder())) {
  1641. return {};
  1642. }
  1643. return storage;
  1644. }
  1645. template<typename TStorage>
  1646. TMaybe<TStorage> StartOfMonth(TStorage storage, const IValueBuilder& valueBuilder) {
  1647. storage.Day = 1;
  1648. SetStartOfDay(storage);
  1649. if (!storage.Validate(valueBuilder.GetDateBuilder())) {
  1650. return {};
  1651. }
  1652. return storage;
  1653. }
  1654. template<typename TStorage>
  1655. TMaybe<TStorage> EndOfMonth(TStorage storage, const IValueBuilder& valueBuilder) {
  1656. storage.Day = NMiniKQL::GetMonthLength(storage.Month, NMiniKQL::IsLeapYear(storage.Year));
  1657. SetEndOfDay(storage);
  1658. if (!storage.Validate(valueBuilder.GetDateBuilder())) {
  1659. return {};
  1660. }
  1661. return storage;
  1662. }
  1663. template<typename TStorage>
  1664. TMaybe<TStorage> StartOfWeek(TStorage storage, const IValueBuilder& valueBuilder) {
  1665. const ui32 shift = 86400u * (storage.DayOfWeek - 1u);
  1666. if constexpr (std::is_same_v<TStorage, TTMStorage>) {
  1667. if (shift > storage.ToDatetime(valueBuilder.GetDateBuilder())) {
  1668. return {};
  1669. }
  1670. storage.FromDatetime(valueBuilder.GetDateBuilder(), storage.ToDatetime(valueBuilder.GetDateBuilder()) - shift, storage.TimezoneId);
  1671. } else {
  1672. if (shift > storage.ToDatetime64(valueBuilder.GetDateBuilder())) {
  1673. return {};
  1674. }
  1675. storage.FromDatetime64(valueBuilder.GetDateBuilder(), storage.ToDatetime64(valueBuilder.GetDateBuilder()) - shift, storage.TimezoneId);
  1676. }
  1677. SetStartOfDay(storage);
  1678. if (!storage.Validate(valueBuilder.GetDateBuilder())) {
  1679. return {};
  1680. }
  1681. return storage;
  1682. }
  1683. template<typename TStorage>
  1684. TMaybe<TStorage> EndOfWeek(TStorage storage, const IValueBuilder& valueBuilder) {
  1685. const ui32 shift = 86400u * (7u - storage.DayOfWeek);
  1686. if constexpr (std::is_same_v<TStorage, TTMStorage>) {
  1687. auto dt = storage.ToDatetime(valueBuilder.GetDateBuilder());
  1688. if (NUdf::MAX_DATETIME - shift <= dt) {
  1689. return {};
  1690. }
  1691. storage.FromDatetime(valueBuilder.GetDateBuilder(), dt + shift, storage.TimezoneId);
  1692. } else {
  1693. auto dt = storage.ToDatetime64(valueBuilder.GetDateBuilder());
  1694. if (NUdf::MAX_DATETIME64 - shift <= dt) {
  1695. return {};
  1696. }
  1697. storage.FromDatetime64(valueBuilder.GetDateBuilder(), dt + shift, storage.TimezoneId);
  1698. }
  1699. SetEndOfDay(storage);
  1700. if (!storage.Validate(valueBuilder.GetDateBuilder())) {
  1701. return {};
  1702. }
  1703. return storage;
  1704. }
  1705. template<typename TStorage>
  1706. TMaybe<TStorage> StartOfDay(TStorage storage, const IValueBuilder& valueBuilder) {
  1707. SetStartOfDay(storage);
  1708. auto& builder = valueBuilder.GetDateBuilder();
  1709. if (!storage.Validate(builder)) {
  1710. return {};
  1711. }
  1712. return storage;
  1713. }
  1714. template<typename TStorage>
  1715. TMaybe<TStorage> EndOfDay(TStorage storage, const IValueBuilder& valueBuilder) {
  1716. SetEndOfDay(storage);
  1717. auto& builder = valueBuilder.GetDateBuilder();
  1718. if (!storage.Validate(builder)) {
  1719. return {};
  1720. }
  1721. return storage;
  1722. }
  1723. template<typename TStorage>
  1724. TMaybe<TStorage> StartOf(TStorage storage, ui64 interval, const IValueBuilder& valueBuilder) {
  1725. if (interval >= 86400000000ull) {
  1726. // treat as StartOfDay
  1727. SetStartOfDay(storage);
  1728. } else {
  1729. auto current = storage.ToTimeOfDay();
  1730. auto rounded = current / interval * interval;
  1731. storage.FromTimeOfDay(rounded);
  1732. }
  1733. auto& builder = valueBuilder.GetDateBuilder();
  1734. if (!storage.Validate(builder)) {
  1735. return {};
  1736. }
  1737. return storage;
  1738. }
  1739. template<typename TStorage>
  1740. TMaybe<TStorage> EndOf(TStorage storage, ui64 interval, const IValueBuilder& valueBuilder) {
  1741. if (interval >= 86400000000ull) {
  1742. // treat as EndOfDay
  1743. SetEndOfDay(storage);
  1744. } else {
  1745. auto current = storage.ToTimeOfDay();
  1746. auto rounded = current / interval * interval + interval - 1;
  1747. storage.FromTimeOfDay(rounded);
  1748. }
  1749. auto& builder = valueBuilder.GetDateBuilder();
  1750. if (!storage.Validate(builder)) {
  1751. return {};
  1752. }
  1753. return storage;
  1754. }
  1755. template<bool UseEnd>
  1756. struct TStartEndOfBinaryKernelExec : TBinaryKernelExec<TStartEndOfBinaryKernelExec<UseEnd>> {
  1757. template<typename TSink>
  1758. static void Process(const IValueBuilder* valueBuilder, TBlockItem arg1, TBlockItem arg2, const TSink& sink) {
  1759. auto& storage = Reference(arg1);
  1760. ui64 interval = std::abs(arg2.Get<i64>());
  1761. if (interval == 0) {
  1762. sink(arg1);
  1763. return;
  1764. }
  1765. if (auto res = (UseEnd ? EndOf<TTMStorage> : StartOf<TTMStorage>)(storage, interval, *valueBuilder)) {
  1766. storage = res.GetRef();
  1767. sink(arg1);
  1768. } else {
  1769. sink(TBlockItem{});
  1770. }
  1771. }
  1772. };
  1773. template<const char* TResourceName, auto Core>
  1774. TUnboxedValue SimpleDatetimeToIntervalUdf(const IValueBuilder* valueBuilder, const TUnboxedValuePod* args) {
  1775. auto result = args[0];
  1776. ui64 interval = std::abs(args[1].Get<i64>());
  1777. if (interval == 0) {
  1778. return result;
  1779. }
  1780. auto& storage = Reference<TResourceName>(result);
  1781. if (auto res = Core(storage, interval, *valueBuilder)) {
  1782. storage = res.GetRef();
  1783. return result;
  1784. }
  1785. return TUnboxedValuePod{};
  1786. }
  1787. template<const char* TUdfName, auto Boundary, auto WBoundary>
  1788. class TBoundaryOfInterval: public ::NYql::NUdf::TBoxedValue {
  1789. public:
  1790. typedef bool TTypeAwareMarker;
  1791. static const TStringRef& Name() {
  1792. static auto name = TStringRef(TUdfName, std::strlen(TUdfName));
  1793. return name;
  1794. }
  1795. static bool DeclareSignature(
  1796. const ::NYql::NUdf::TStringRef& name,
  1797. ::NYql::NUdf::TType* userType,
  1798. ::NYql::NUdf::IFunctionTypeInfoBuilder& builder,
  1799. bool typesOnly)
  1800. {
  1801. if (Name() != name) {
  1802. return false;
  1803. }
  1804. if (!userType) {
  1805. builder.SetError("User type is missing");
  1806. return true;
  1807. }
  1808. builder.UserType(userType);
  1809. const auto typeInfoHelper = builder.TypeInfoHelper();
  1810. TTupleTypeInspector tuple(*typeInfoHelper, userType);
  1811. Y_ENSURE(tuple, "Tuple with args and options tuples expected");
  1812. Y_ENSURE(tuple.GetElementsCount() > 0,
  1813. "Tuple has to contain positional arguments");
  1814. TTupleTypeInspector argsTuple(*typeInfoHelper, tuple.GetElementType(0));
  1815. Y_ENSURE(argsTuple, "Tuple with args expected");
  1816. if (argsTuple.GetElementsCount() != 2) {
  1817. builder.SetError("Single argument expected");
  1818. return true;
  1819. }
  1820. auto argType = argsTuple.GetElementType(0);
  1821. if (const auto optType = TOptionalTypeInspector(*typeInfoHelper, argType)) {
  1822. argType = optType.GetItemType();
  1823. }
  1824. TResourceTypeInspector resource(*typeInfoHelper, argType);
  1825. if (!resource) {
  1826. TDataTypeInspector data(*typeInfoHelper, argType);
  1827. if (!data) {
  1828. SetInvalidTypeError(builder, typeInfoHelper, argType);
  1829. return true;
  1830. }
  1831. const auto features = NUdf::GetDataTypeInfo(NUdf::GetDataSlot(data.GetTypeId())).Features;
  1832. if (features & NUdf::BigDateType) {
  1833. BuildSignature<TM64ResourceName, WBoundary>(builder, typesOnly);
  1834. return true;
  1835. }
  1836. if (features & (NUdf::DateType | NUdf::TzDateType)) {
  1837. BuildSignature<TMResourceName, Boundary>(builder, typesOnly);
  1838. return true;
  1839. }
  1840. SetInvalidTypeError(builder, typeInfoHelper, argType);
  1841. return true;
  1842. }
  1843. if (resource.GetTag() == TStringRef::Of(TM64ResourceName)) {
  1844. BuildSignature<TM64ResourceName, WBoundary>(builder, typesOnly);
  1845. return true;
  1846. }
  1847. if (resource.GetTag() == TStringRef::Of(TMResourceName)) {
  1848. BuildSignature<TMResourceName, Boundary>(builder, typesOnly);
  1849. return true;
  1850. }
  1851. ::TStringBuilder sb;
  1852. sb << "Unexpected Resource tag: got '" << resource.GetTag() << "'";
  1853. builder.SetError(sb);
  1854. return true;
  1855. }
  1856. private:
  1857. template<auto Func>
  1858. class TImpl : public TBoxedValue {
  1859. public:
  1860. TUnboxedValue Run(const IValueBuilder* valueBuilder, const TUnboxedValuePod* args) const final {
  1861. try {
  1862. return Func(valueBuilder, args);
  1863. } catch (const std::exception&) {
  1864. TStringBuilder sb;
  1865. sb << CurrentExceptionMessage();
  1866. sb << Endl << "[" << TStringBuf(Name()) << "]" ;
  1867. UdfTerminate(sb.c_str());
  1868. }
  1869. }
  1870. };
  1871. static void SetInvalidTypeError(NUdf::IFunctionTypeInfoBuilder& builder,
  1872. ITypeInfoHelper::TPtr typeInfoHelper, const TType* argType)
  1873. {
  1874. ::TStringBuilder sb;
  1875. sb << "Invalid argument type: got ";
  1876. TTypePrinter(*typeInfoHelper, argType).Out(sb.Out);
  1877. sb << ", but Resource<" << TMResourceName <<"> or Resource<"
  1878. << TM64ResourceName << "> expected";
  1879. builder.SetError(sb);
  1880. }
  1881. template<const char* TResourceName, auto Func>
  1882. static void BuildSignature(NUdf::IFunctionTypeInfoBuilder& builder, bool typesOnly) {
  1883. builder.Returns<TOptional<TResource<TResourceName>>>();
  1884. builder.Args()->Add<TAutoMap<TResource<TResourceName>>>()
  1885. .template Add<TAutoMap<std::conditional_t<TResourceName == TMResourceName, TInterval, TInterval64>>>();
  1886. builder.IsStrict();
  1887. if (!typesOnly) {
  1888. builder.Implementation(new TImpl<Func>());
  1889. }
  1890. }
  1891. };
  1892. struct TTimeOfDayKernelExec : TUnaryKernelExec<TTimeOfDayKernelExec, TReaderTraits::TResource<false>, TFixedSizeArrayBuilder<TDataType<TInterval>::TLayout, false>> {
  1893. template<typename TSink>
  1894. static void Process(const IValueBuilder* valueBuilder, TBlockItem item, const TSink& sink) {
  1895. Y_UNUSED(valueBuilder);
  1896. auto& storage = Reference(item);
  1897. sink(TBlockItem{(TDataType<TInterval>::TLayout)storage.ToTimeOfDay()});
  1898. }
  1899. };
  1900. class TTimeOfDay: public ::NYql::NUdf::TBoxedValue {
  1901. public:
  1902. typedef bool TTypeAwareMarker;
  1903. static const ::NYql::NUdf::TStringRef& Name() {
  1904. static auto name = TStringRef::Of("TimeOfDay");
  1905. return name;
  1906. }
  1907. static bool DeclareSignature(
  1908. const ::NYql::NUdf::TStringRef& name,
  1909. ::NYql::NUdf::TType* userType,
  1910. ::NYql::NUdf::IFunctionTypeInfoBuilder& builder,
  1911. bool typesOnly)
  1912. {
  1913. if (Name() != name) {
  1914. return false;
  1915. }
  1916. if (!userType) {
  1917. builder.SetError("User type is missing");
  1918. return true;
  1919. }
  1920. builder.UserType(userType);
  1921. const auto typeInfoHelper = builder.TypeInfoHelper();
  1922. TTupleTypeInspector tuple(*typeInfoHelper, userType);
  1923. Y_ENSURE(tuple, "Tuple with args and options tuples expected");
  1924. Y_ENSURE(tuple.GetElementsCount() > 0,
  1925. "Tuple has to contain positional arguments");
  1926. TTupleTypeInspector argsTuple(*typeInfoHelper, tuple.GetElementType(0));
  1927. Y_ENSURE(argsTuple, "Tuple with args expected");
  1928. if (argsTuple.GetElementsCount() != 1) {
  1929. builder.SetError("Single argument expected");
  1930. return true;
  1931. }
  1932. auto argType = argsTuple.GetElementType(0);
  1933. if (const auto optType = TOptionalTypeInspector(*typeInfoHelper, argType)) {
  1934. argType = optType.GetItemType();
  1935. }
  1936. TResourceTypeInspector resource(*typeInfoHelper, argType);
  1937. if (!resource) {
  1938. TDataTypeInspector data(*typeInfoHelper, argType);
  1939. if (!data) {
  1940. SetInvalidTypeError(builder, typeInfoHelper, argType);
  1941. return true;
  1942. }
  1943. const auto features = NUdf::GetDataTypeInfo(NUdf::GetDataSlot(data.GetTypeId())).Features;
  1944. if (features & NUdf::BigDateType) {
  1945. BuildSignature<TM64ResourceName>(builder, typesOnly);
  1946. return true;
  1947. }
  1948. if (features & (NUdf::DateType | NUdf::TzDateType)) {
  1949. BuildSignature<TMResourceName>(builder, typesOnly);
  1950. return true;
  1951. }
  1952. SetInvalidTypeError(builder, typeInfoHelper, argType);
  1953. return true;
  1954. }
  1955. if (resource.GetTag() == TStringRef::Of(TM64ResourceName)) {
  1956. BuildSignature<TM64ResourceName>(builder, typesOnly);
  1957. return true;
  1958. }
  1959. if (resource.GetTag() == TStringRef::Of(TMResourceName)) {
  1960. BuildSignature<TMResourceName>(builder, typesOnly);
  1961. return true;
  1962. }
  1963. ::TStringBuilder sb;
  1964. sb << "Unexpected Resource tag: got '" << resource.GetTag() << "'";
  1965. builder.SetError(sb);
  1966. return true;
  1967. }
  1968. private:
  1969. template<const char* TResourceName>
  1970. class TImpl : public TBoxedValue {
  1971. public:
  1972. TUnboxedValue Run(const IValueBuilder* valueBuilder, const TUnboxedValuePod* args) const final {
  1973. try {
  1974. Y_UNUSED(valueBuilder);
  1975. auto& storage = Reference<TResourceName>(args[0]);
  1976. return TUnboxedValuePod((i64)storage.ToTimeOfDay());
  1977. } catch (const std::exception&) {
  1978. TStringBuilder sb;
  1979. sb << CurrentExceptionMessage();
  1980. sb << Endl << "[" << TStringBuf(Name()) << "]" ;
  1981. UdfTerminate(sb.c_str());
  1982. }
  1983. }
  1984. };
  1985. static void SetInvalidTypeError(NUdf::IFunctionTypeInfoBuilder& builder,
  1986. ITypeInfoHelper::TPtr typeInfoHelper, const TType* argType)
  1987. {
  1988. ::TStringBuilder sb;
  1989. sb << "Invalid argument type: got ";
  1990. TTypePrinter(*typeInfoHelper, argType).Out(sb.Out);
  1991. sb << ", but Resource<" << TMResourceName <<"> or Resource<"
  1992. << TM64ResourceName << "> expected";
  1993. builder.SetError(sb);
  1994. }
  1995. template< const char* TResourceName>
  1996. static void BuildSignature(NUdf::IFunctionTypeInfoBuilder& builder, bool typesOnly) {
  1997. builder.Returns<std::conditional_t<TResourceName == TMResourceName, TInterval, TInterval64>>();
  1998. builder.Args()->Add<TAutoMap<TResource<TResourceName>>>();
  1999. builder.IsStrict();
  2000. if (!typesOnly) {
  2001. builder.Implementation(new TImpl<TResourceName>());
  2002. }
  2003. }
  2004. };
  2005. // Add ...
  2006. template<auto Core>
  2007. struct TAddKernelExec : TBinaryKernelExec<TAddKernelExec<Core>> {
  2008. template<typename TSink>
  2009. static void Process(const IValueBuilder* valueBuilder, TBlockItem date, TBlockItem arg, const TSink& sink) {
  2010. sink(Core(date, arg.Get<i32>(), valueBuilder->GetDateBuilder()));
  2011. }
  2012. };
  2013. template<const char* TUdfName, auto Shifter, auto WShifter>
  2014. class TShift : public TBoxedValue {
  2015. public:
  2016. typedef bool TTypeAwareMarker;
  2017. static const TStringRef& Name() {
  2018. static auto name = TStringRef(TUdfName, std::strlen(TUdfName));
  2019. return name;
  2020. }
  2021. static bool DeclareSignature(
  2022. const TStringRef& name,
  2023. TType* userType,
  2024. IFunctionTypeInfoBuilder& builder,
  2025. bool typesOnly)
  2026. {
  2027. if (Name() != name) {
  2028. return false;
  2029. }
  2030. if (!userType) {
  2031. builder.SetError("User type is missing");
  2032. return true;
  2033. }
  2034. builder.UserType(userType);
  2035. const auto typeInfoHelper = builder.TypeInfoHelper();
  2036. TTupleTypeInspector tuple(*typeInfoHelper, userType);
  2037. Y_ENSURE(tuple, "Tuple with args and options tuples expected");
  2038. Y_ENSURE(tuple.GetElementsCount() > 0,
  2039. "Tuple has to contain positional arguments");
  2040. TTupleTypeInspector argsTuple(*typeInfoHelper, tuple.GetElementType(0));
  2041. Y_ENSURE(argsTuple, "Tuple with args expected");
  2042. if (argsTuple.GetElementsCount() != 2) {
  2043. builder.SetError("Only two arguments expected");
  2044. return true;
  2045. }
  2046. auto argType = argsTuple.GetElementType(0);
  2047. if (const auto optType = TOptionalTypeInspector(*typeInfoHelper, argType)) {
  2048. argType = optType.GetItemType();
  2049. }
  2050. TResourceTypeInspector resource(*typeInfoHelper, argType);
  2051. if (!resource) {
  2052. TDataTypeInspector data(*typeInfoHelper, argType);
  2053. if (!data) {
  2054. SetInvalidTypeError(builder, typeInfoHelper, argType);
  2055. return true;
  2056. }
  2057. const auto features = NUdf::GetDataTypeInfo(NUdf::GetDataSlot(data.GetTypeId())).Features;
  2058. if (features & NUdf::BigDateType) {
  2059. BuildSignature<TM64ResourceName, WShifter>(builder, typesOnly);
  2060. return true;
  2061. }
  2062. if (features & (NUdf::DateType | NUdf::TzDateType)) {
  2063. BuildSignature<TMResourceName, Shifter>(builder, typesOnly);
  2064. return true;
  2065. }
  2066. SetInvalidTypeError(builder, typeInfoHelper, argType);
  2067. return true;
  2068. }
  2069. if (resource.GetTag() == TStringRef::Of(TM64ResourceName)) {
  2070. BuildSignature<TM64ResourceName, WShifter>(builder, typesOnly);
  2071. return true;
  2072. }
  2073. if (resource.GetTag() == TStringRef::Of(TMResourceName)) {
  2074. BuildSignature<TMResourceName, Shifter>(builder, typesOnly);
  2075. return true;
  2076. }
  2077. ::TStringBuilder sb;
  2078. sb << "Unexpected Resource tag: got '" << resource.GetTag() << "'";
  2079. builder.SetError(sb);
  2080. return true;
  2081. }
  2082. private:
  2083. template<auto ShiftHanler>
  2084. class TImpl : public TBoxedValue {
  2085. public:
  2086. TUnboxedValue Run(const IValueBuilder* valueBuilder, const TUnboxedValuePod* args) const final {
  2087. return ShiftHanler(args[0], args[1].Get<i32>(), valueBuilder->GetDateBuilder());
  2088. }
  2089. };
  2090. static void SetInvalidTypeError(NUdf::IFunctionTypeInfoBuilder& builder,
  2091. ITypeInfoHelper::TPtr typeInfoHelper, const TType* argType)
  2092. {
  2093. ::TStringBuilder sb;
  2094. sb << "Invalid argument type: got ";
  2095. TTypePrinter(*typeInfoHelper, argType).Out(sb.Out);
  2096. sb << ", but Resource<" << TMResourceName <<"> or Resource<"
  2097. << TM64ResourceName << "> expected";
  2098. builder.SetError(sb);
  2099. }
  2100. template<const char* TResourceName, auto ShiftHandler>
  2101. static void BuildSignature(NUdf::IFunctionTypeInfoBuilder& builder, bool typesOnly) {
  2102. builder.Returns<TOptional<TResource<TResourceName>>>();
  2103. builder.Args()->Add<TAutoMap<TResource<TResourceName>>>().template Add<i32>();
  2104. builder.IsStrict();
  2105. if (!typesOnly) {
  2106. builder.Implementation(new TImpl<ShiftHandler>());
  2107. }
  2108. }
  2109. };
  2110. template<size_t Digits, bool Exacly = true>
  2111. struct PrintNDigits;
  2112. template<bool Exacly>
  2113. struct PrintNDigits<0U, Exacly> {
  2114. static constexpr ui32 Miltiplier = 1U;
  2115. template <typename T>
  2116. static constexpr size_t Do(T, char*) { return 0U; }
  2117. };
  2118. template<size_t Digits, bool Exacly>
  2119. struct PrintNDigits {
  2120. using TNextPrint = PrintNDigits<Digits - 1U, Exacly>;
  2121. static constexpr ui32 Miltiplier = TNextPrint::Miltiplier * 10U;
  2122. template <typename T>
  2123. static constexpr size_t Do(T in, char* out) {
  2124. in %= Miltiplier;
  2125. if (Exacly || in) {
  2126. *out = "0123456789"[in / TNextPrint::Miltiplier];
  2127. return 1U + TNextPrint::Do(in, ++out);
  2128. }
  2129. return 0U;
  2130. }
  2131. };
  2132. // Format
  2133. class TFormat : public TBoxedValue {
  2134. public:
  2135. explicit TFormat(TSourcePosition pos)
  2136. : Pos_(pos)
  2137. {}
  2138. static const TStringRef& Name() {
  2139. static auto name = TStringRef::Of("Format");
  2140. return name;
  2141. }
  2142. static bool DeclareSignature(
  2143. const TStringRef& name,
  2144. TType*,
  2145. IFunctionTypeInfoBuilder& builder,
  2146. bool typesOnly)
  2147. {
  2148. if (Name() != name) {
  2149. return false;
  2150. }
  2151. auto resourceType = builder.Resource(TMResourceName);
  2152. auto stringType = builder.SimpleType<char*>();
  2153. auto boolType = builder.SimpleType<bool>();
  2154. auto optionalBoolType = builder.Optional()->Item(boolType).Build();
  2155. auto args = builder.Args();
  2156. args->Add(stringType);
  2157. args->Add(optionalBoolType).Name("AlwaysWriteFractionalSeconds");
  2158. args->Done();
  2159. builder.OptionalArgs(1);
  2160. builder.Returns(
  2161. builder.Callable(1)
  2162. ->Returns(stringType)
  2163. .Arg(resourceType)
  2164. .Flags(ICallablePayload::TArgumentFlags::AutoMap)
  2165. .Build()
  2166. );
  2167. if (!typesOnly) {
  2168. builder.Implementation(new TFormat(builder.GetSourcePosition()));
  2169. }
  2170. return true;
  2171. }
  2172. private:
  2173. using TPrintersList = std::vector<std::function<size_t(char*, const TUnboxedValuePod&, const IDateBuilder&)>>;
  2174. struct TDataPrinter {
  2175. const std::string_view Data;
  2176. size_t operator()(char* out, const TUnboxedValuePod&, const IDateBuilder&) const {
  2177. std::memcpy(out, Data.data(), Data.size());
  2178. return Data.size();
  2179. }
  2180. };
  2181. TUnboxedValue Run(const IValueBuilder*, const TUnboxedValuePod* args) const final try {
  2182. bool alwaysWriteFractionalSeconds = false;
  2183. if (auto val = args[1]) {
  2184. alwaysWriteFractionalSeconds = val.Get<bool>();
  2185. }
  2186. return TUnboxedValuePod(new TImpl(Pos_, args[0], alwaysWriteFractionalSeconds));
  2187. } catch (const std::exception& e) {
  2188. UdfTerminate((TStringBuilder() << Pos_ << " " << e.what()).data());
  2189. }
  2190. class TImpl : public TBoxedValue {
  2191. public:
  2192. TUnboxedValue Run(
  2193. const IValueBuilder* valueBuilder,
  2194. const TUnboxedValuePod* args) const override
  2195. {
  2196. try {
  2197. EMPTY_RESULT_ON_EMPTY_ARG(0);
  2198. const auto value = args[0];
  2199. auto& builder = valueBuilder->GetDateBuilder();
  2200. auto result = valueBuilder->NewStringNotFilled(ReservedSize_);
  2201. auto pos = result.AsStringRef().Data();
  2202. ui32 size = 0U;
  2203. for (const auto& printer : Printers_) {
  2204. if (const auto plus = printer(pos, value, builder)) {
  2205. size += plus;
  2206. pos += plus;
  2207. }
  2208. }
  2209. if (size < ReservedSize_) {
  2210. result = valueBuilder->SubString(result.Release(), 0U, size);
  2211. }
  2212. return result;
  2213. } catch (const std::exception& e) {
  2214. UdfTerminate((TStringBuilder() << Pos_ << " " << e.what()).data());
  2215. }
  2216. }
  2217. TImpl(TSourcePosition pos, TUnboxedValue format, bool alwaysWriteFractionalSeconds)
  2218. : Pos_(pos)
  2219. , Format_(format)
  2220. {
  2221. const std::string_view formatView(Format_.AsStringRef());
  2222. auto dataStart = formatView.begin();
  2223. size_t dataSize = 0U;
  2224. for (auto ptr = formatView.begin(); formatView.end() != ptr; ++ptr) {
  2225. if (*ptr != '%') {
  2226. ++dataSize;
  2227. continue;
  2228. }
  2229. if (dataSize) {
  2230. Printers_.emplace_back(TDataPrinter{std::string_view(&*dataStart, dataSize)});
  2231. ReservedSize_ += dataSize;
  2232. dataSize = 0U;
  2233. }
  2234. if (formatView.end() == ++ptr) {
  2235. ythrow yexception() << "format string ends with single %%";
  2236. }
  2237. switch (*ptr) {
  2238. case '%': {
  2239. static constexpr size_t size = 1;
  2240. Printers_.emplace_back([](char* out, const TUnboxedValuePod&, const IDateBuilder&) {
  2241. *out = '%';
  2242. return size;
  2243. });
  2244. ReservedSize_ += size;
  2245. break;
  2246. }
  2247. case 'Y': {
  2248. static constexpr size_t size = 4;
  2249. Printers_.emplace_back([](char* out, const TUnboxedValuePod& value, const IDateBuilder&) {
  2250. return PrintNDigits<size>::Do(GetYear(value), out);
  2251. });
  2252. ReservedSize_ += size;
  2253. break;
  2254. }
  2255. case 'm': {
  2256. static constexpr size_t size = 2;
  2257. Printers_.emplace_back([](char* out, const TUnboxedValuePod& value, const IDateBuilder&) {
  2258. return PrintNDigits<size>::Do(GetMonth(value), out);
  2259. });
  2260. ReservedSize_ += size;
  2261. break;
  2262. }
  2263. case 'd': {
  2264. static constexpr size_t size = 2;
  2265. Printers_.emplace_back([](char* out, const TUnboxedValuePod& value, const IDateBuilder&) {
  2266. return PrintNDigits<size>::Do(GetDay(value), out);
  2267. });
  2268. ReservedSize_ += size;
  2269. break;
  2270. }
  2271. case 'H': {
  2272. static constexpr size_t size = 2;
  2273. Printers_.emplace_back([](char* out, const TUnboxedValuePod& value, const IDateBuilder&) {
  2274. return PrintNDigits<size>::Do(GetHour(value), out);
  2275. });
  2276. ReservedSize_ += size;
  2277. break;
  2278. }
  2279. case 'M': {
  2280. static constexpr size_t size = 2;
  2281. Printers_.emplace_back([](char* out, const TUnboxedValuePod& value, const IDateBuilder&) {
  2282. return PrintNDigits<size>::Do(GetMinute(value), out);
  2283. });
  2284. ReservedSize_ += size;
  2285. break;
  2286. }
  2287. case 'S':
  2288. Printers_.emplace_back([alwaysWriteFractionalSeconds](char* out, const TUnboxedValuePod& value, const IDateBuilder&) {
  2289. constexpr size_t size = 2;
  2290. if (const auto microsecond = GetMicrosecond(value); microsecond || alwaysWriteFractionalSeconds) {
  2291. out += PrintNDigits<size>::Do(GetSecond(value), out);
  2292. *out++ = '.';
  2293. constexpr size_t msize = 6;
  2294. auto addSz = alwaysWriteFractionalSeconds ?
  2295. PrintNDigits<msize, true>::Do(microsecond, out) :
  2296. PrintNDigits<msize, false>::Do(microsecond, out);
  2297. return size + 1U + addSz;
  2298. }
  2299. return PrintNDigits<size>::Do(GetSecond(value), out);
  2300. });
  2301. ReservedSize_ += 9;
  2302. break;
  2303. case 'z': {
  2304. static constexpr size_t size = 5;
  2305. Printers_.emplace_back([](char* out, const TUnboxedValuePod& value, const IDateBuilder& builder) {
  2306. auto timezoneId = GetTimezoneId(value);
  2307. if (TTMStorage::IsUniversal(timezoneId)) {
  2308. std::memcpy(out, "+0000", size);
  2309. return size;
  2310. }
  2311. i32 shift;
  2312. if (!builder.GetTimezoneShift(GetYear(value), GetMonth(value), GetDay(value),
  2313. GetHour(value), GetMinute(value), GetSecond(value), timezoneId, shift))
  2314. {
  2315. std::memcpy(out, "+0000", size);
  2316. return size;
  2317. }
  2318. *out++ = shift > 0 ? '+' : '-';
  2319. shift = std::abs(shift);
  2320. out += PrintNDigits<2U>::Do(shift / 60U, out);
  2321. out += PrintNDigits<2U>::Do(shift % 60U, out);
  2322. return size;
  2323. });
  2324. ReservedSize_ += size;
  2325. break;
  2326. }
  2327. case 'Z':
  2328. Printers_.emplace_back([](char* out, const TUnboxedValuePod& value, const IDateBuilder&) {
  2329. const auto timezoneId = GetTimezoneId(value);
  2330. const auto tzName = NUdf::GetTimezones()[timezoneId];
  2331. std::memcpy(out, tzName.data(), std::min(tzName.size(), MAX_TIMEZONE_NAME_LEN));
  2332. return tzName.size();
  2333. });
  2334. ReservedSize_ += MAX_TIMEZONE_NAME_LEN;
  2335. break;
  2336. case 'b': {
  2337. static constexpr size_t size = 3;
  2338. Printers_.emplace_back([](char* out, const TUnboxedValuePod& value, const IDateBuilder&) {
  2339. static constexpr std::string_view mp[] {
  2340. "Jan",
  2341. "Feb",
  2342. "Mar",
  2343. "Apr",
  2344. "May",
  2345. "Jun",
  2346. "Jul",
  2347. "Aug",
  2348. "Sep",
  2349. "Oct",
  2350. "Nov",
  2351. "Dec"
  2352. };
  2353. auto month = GetMonth(value);
  2354. Y_ENSURE(month > 0 && month <= sizeof(mp) / sizeof(mp[0]), "Invalid month value");
  2355. std::memcpy(out, mp[month - 1].data(), size);
  2356. return size;
  2357. });
  2358. ReservedSize_ += size;
  2359. break;
  2360. }
  2361. case 'B': {
  2362. Printers_.emplace_back([](char* out, const TUnboxedValuePod& value, const IDateBuilder&) {
  2363. static constexpr std::string_view mp[] {
  2364. "January",
  2365. "February",
  2366. "March",
  2367. "April",
  2368. "May",
  2369. "June",
  2370. "July",
  2371. "August",
  2372. "September",
  2373. "October",
  2374. "November",
  2375. "December"
  2376. };
  2377. auto month = GetMonth(value);
  2378. Y_ENSURE(month > 0 && month <= sizeof(mp) / sizeof(mp[0]), "Invalid month value");
  2379. const std::string_view monthFullName = mp[month - 1];
  2380. std::memcpy(out, monthFullName.data(), monthFullName.size());
  2381. return monthFullName.size();
  2382. });
  2383. ReservedSize_ += 9U; // MAX_MONTH_FULL_NAME_LEN
  2384. break;
  2385. }
  2386. default:
  2387. ythrow yexception() << "invalid format character: " << *ptr;
  2388. }
  2389. dataStart = ptr + 1U;
  2390. }
  2391. if (dataSize) {
  2392. Printers_.emplace_back(TDataPrinter{std::string_view(dataStart, dataSize)});
  2393. ReservedSize_ += dataSize;
  2394. }
  2395. }
  2396. private:
  2397. const TSourcePosition Pos_;
  2398. TUnboxedValue Format_;
  2399. TPrintersList Printers_{};
  2400. size_t ReservedSize_ = 0;
  2401. };
  2402. const TSourcePosition Pos_;
  2403. };
  2404. template<size_t Digits, bool Variable = false>
  2405. struct ParseNDigits;
  2406. template<bool Variable>
  2407. struct ParseNDigits<0U, Variable> {
  2408. template <typename T>
  2409. static constexpr bool Do(std::string_view::const_iterator&, T&) {
  2410. return true;
  2411. }
  2412. };
  2413. template<size_t Digits, bool Variable>
  2414. struct ParseNDigits {
  2415. template <typename T>
  2416. static constexpr bool Do(std::string_view::const_iterator& it, T& out) {
  2417. const auto d = *it;
  2418. if (!std::isdigit(d)) {
  2419. // XXX: If the current char is not a digit, the
  2420. // parsing succeeds iff there are no more digits
  2421. // to be parsed (see the class specialization
  2422. // above) or there are given less than N digits
  2423. // to be parsed.
  2424. if constexpr (Variable) {
  2425. return true;
  2426. }
  2427. return false;
  2428. }
  2429. out *= 10U;
  2430. out += d - '0';
  2431. return ParseNDigits<Digits - 1U, Variable>::Do(++it, out);
  2432. }
  2433. };
  2434. // Parse
  2435. template<const char* TUdfName, const char* TResourceName>
  2436. class TParse : public TBoxedValue {
  2437. public:
  2438. class TFactory : public TBoxedValue {
  2439. public:
  2440. explicit TFactory(TSourcePosition pos)
  2441. : Pos_(pos)
  2442. {}
  2443. private:
  2444. TUnboxedValue Run(const IValueBuilder*, const TUnboxedValuePod* args) const final try {
  2445. return TUnboxedValuePod(new TParse(args[0], Pos_));
  2446. } catch (const std::exception& e) {
  2447. UdfTerminate((TStringBuilder() << Pos_ << " " << e.what()).data());
  2448. }
  2449. const TSourcePosition Pos_;
  2450. };
  2451. static const TStringRef& Name() {
  2452. static auto name = TStringRef(TUdfName, std::strlen(TUdfName));
  2453. return name;
  2454. }
  2455. static bool DeclareSignature(
  2456. const TStringRef& name,
  2457. TType*,
  2458. IFunctionTypeInfoBuilder& builder,
  2459. bool typesOnly)
  2460. {
  2461. if (Name() != name) {
  2462. return false;
  2463. }
  2464. builder.OptionalArgs(1).Args()->Add<char*>()
  2465. .template Add<TOptional<ui16>>();
  2466. builder.Returns(
  2467. builder.SimpleSignatureType<TOptional<TResource<TResourceName>>(TAutoMap<char*>)>());
  2468. if (!typesOnly) {
  2469. builder.Implementation(new TParse::TFactory(builder.GetSourcePosition()));
  2470. }
  2471. return true;
  2472. }
  2473. private:
  2474. const TSourcePosition Pos_;
  2475. const TUnboxedValue Format_;
  2476. std::vector<std::function<bool(std::string_view::const_iterator& it, size_t, TUnboxedValuePod&, const IDateBuilder&)>> Scanners_;
  2477. struct TDataScanner {
  2478. const std::string_view Data_;
  2479. bool operator()(std::string_view::const_iterator& it, size_t limit, TUnboxedValuePod&, const IDateBuilder&) const {
  2480. if (limit < Data_.size() || !std::equal(Data_.begin(), Data_.end(), it)) {
  2481. return false;
  2482. }
  2483. std::advance(it, Data_.size());
  2484. return true;
  2485. }
  2486. };
  2487. TUnboxedValue Run(
  2488. const IValueBuilder* valueBuilder,
  2489. const TUnboxedValuePod* args) const override
  2490. {
  2491. try {
  2492. EMPTY_RESULT_ON_EMPTY_ARG(0);
  2493. const std::string_view buffer = args[0].AsStringRef();
  2494. TUnboxedValuePod result(0);
  2495. auto& storage = Reference<TResourceName>(result);
  2496. storage.MakeDefault();
  2497. auto& builder = valueBuilder->GetDateBuilder();
  2498. auto it = buffer.begin();
  2499. for (const auto& scanner : Scanners_) {
  2500. if (!scanner(it, std::distance(it, buffer.end()), result, builder)) {
  2501. return TUnboxedValuePod();
  2502. }
  2503. }
  2504. if (buffer.end() != it || !storage.Validate(builder)) {
  2505. return TUnboxedValuePod();
  2506. }
  2507. return result;
  2508. } catch (const std::exception& e) {
  2509. UdfTerminate((TStringBuilder() << Pos_ << " " << e.what()).data());
  2510. }
  2511. }
  2512. TParse(const TUnboxedValuePod& runConfig, TSourcePosition pos)
  2513. : Pos_(pos)
  2514. , Format_(runConfig)
  2515. {
  2516. const std::string_view formatView(Format_.AsStringRef());
  2517. auto dataStart = formatView.begin();
  2518. size_t dataSize = 0U;
  2519. for (auto ptr = formatView.begin(); formatView.end() != ptr; ++ptr) {
  2520. if (*ptr != '%') {
  2521. ++dataSize;
  2522. continue;
  2523. }
  2524. if (dataSize) {
  2525. Scanners_.emplace_back(TDataScanner{std::string_view(&*dataStart, dataSize)});
  2526. dataSize = 0;
  2527. }
  2528. if (++ptr == formatView.end()) {
  2529. ythrow yexception() << "format string ends with single %%";
  2530. }
  2531. switch (*ptr) {
  2532. case '%':
  2533. Scanners_.emplace_back([](std::string_view::const_iterator& it, size_t limit, TUnboxedValuePod&, const IDateBuilder&) {
  2534. return limit > 0U && *it++ == '%';
  2535. });
  2536. break;
  2537. case 'Y': {
  2538. Scanners_.emplace_back([](std::string_view::const_iterator& it, size_t limit, TUnboxedValuePod& result, const IDateBuilder&) {
  2539. if constexpr (TResourceName == TMResourceName) {
  2540. static constexpr size_t size = 4;
  2541. ui32 year = 0U;
  2542. if (limit < size || !ParseNDigits<size>::Do(it, year) || !ValidateYear(year)) {
  2543. return false;
  2544. }
  2545. SetYear<TMResourceName>(result, year);
  2546. } else {
  2547. static constexpr size_t size = 6;
  2548. i64 year = 0LL;
  2549. i64 negative = 1LL;
  2550. if (*it == '-') {
  2551. negative = -1LL;
  2552. it++;
  2553. }
  2554. if (!ParseNDigits<size, true>::Do(it, year) || !ValidateYear(negative * year)) {
  2555. return false;
  2556. }
  2557. SetYear<TM64ResourceName>(result, negative * year);
  2558. }
  2559. return true;
  2560. });
  2561. break;
  2562. }
  2563. case 'm': {
  2564. static constexpr size_t size = 2;
  2565. Scanners_.emplace_back([](std::string_view::const_iterator& it, size_t limit, TUnboxedValuePod& result, const IDateBuilder&) {
  2566. ui32 month = 0U;
  2567. if (limit < size || !ParseNDigits<size>::Do(it, month) || !ValidateMonth(month)) {
  2568. return false;
  2569. }
  2570. SetMonth<TResourceName>(result, month);
  2571. return true;
  2572. });
  2573. break;
  2574. }
  2575. case 'd': {
  2576. static constexpr size_t size = 2;
  2577. Scanners_.emplace_back([](std::string_view::const_iterator& it, size_t limit, TUnboxedValuePod& result, const IDateBuilder&) {
  2578. ui32 day = 0U;
  2579. if (limit < size || !ParseNDigits<size>::Do(it, day) || !ValidateDay(day)) {
  2580. return false;
  2581. }
  2582. SetDay<TResourceName>(result, day);
  2583. return true;
  2584. });
  2585. break;
  2586. }
  2587. case 'H': {
  2588. static constexpr size_t size = 2;
  2589. Scanners_.emplace_back([](std::string_view::const_iterator& it, size_t limit, TUnboxedValuePod& result, const IDateBuilder&) {
  2590. ui32 hour = 0U;
  2591. if (limit < size || !ParseNDigits<size>::Do(it, hour) || !ValidateHour(hour)) {
  2592. return false;
  2593. }
  2594. SetHour<TResourceName>(result, hour);
  2595. return true;
  2596. });
  2597. break;
  2598. }
  2599. case 'M': {
  2600. static constexpr size_t size = 2;
  2601. Scanners_.emplace_back([](std::string_view::const_iterator& it, size_t limit, TUnboxedValuePod& result, const IDateBuilder&) {
  2602. ui32 minute = 0U;
  2603. if (limit < size || !ParseNDigits<size>::Do(it, minute) || !ValidateMinute(minute)) {
  2604. return false;
  2605. }
  2606. SetMinute<TResourceName>(result, minute);
  2607. return true;
  2608. });
  2609. break;
  2610. }
  2611. case 'S': {
  2612. static constexpr size_t size = 2;
  2613. Scanners_.emplace_back([](std::string_view::const_iterator& it, size_t limit, TUnboxedValuePod& result, const IDateBuilder&) {
  2614. ui32 second = 0U;
  2615. if (limit < size || !ParseNDigits<size>::Do(it, second) || !ValidateSecond(second)) {
  2616. return false;
  2617. }
  2618. SetSecond<TResourceName>(result, second);
  2619. limit -= size;
  2620. if (!limit || *it != '.') {
  2621. return true;
  2622. }
  2623. ++it;
  2624. --limit;
  2625. ui32 usec = 0U;
  2626. size_t digits = 6U;
  2627. for (; limit; --limit) {
  2628. const auto c = *it;
  2629. if (!digits || !std::isdigit(c)) {
  2630. break;
  2631. }
  2632. usec *= 10U;
  2633. usec += c - '0';
  2634. ++it;
  2635. --digits;
  2636. }
  2637. for (; !digits && limit && std::isdigit(*it); --limit, ++it);
  2638. while (digits--) {
  2639. usec *= 10U;
  2640. }
  2641. SetMicrosecond<TResourceName>(result, usec);
  2642. return true;
  2643. });
  2644. break;
  2645. }
  2646. case 'Z':
  2647. Scanners_.emplace_back([](std::string_view::const_iterator& it, size_t limit, TUnboxedValuePod& result, const IDateBuilder& builder) {
  2648. const auto start = it;
  2649. while (limit > 0 && (std::isalnum(*it) || *it == '/' || *it == '_' || *it == '-' || *it == '+')) {
  2650. ++it;
  2651. --limit;
  2652. }
  2653. const auto size = std::distance(start, it);
  2654. ui32 timezoneId;
  2655. if (!builder.FindTimezoneId(TStringRef(&*start, size), timezoneId)) {
  2656. return false;
  2657. }
  2658. SetTimezoneId<TResourceName>(result, timezoneId);
  2659. return true;
  2660. });
  2661. break;
  2662. case 'b': {
  2663. static constexpr size_t size = 3;
  2664. Scanners_.emplace_back([](std::string_view::const_iterator& it, size_t limit, TUnboxedValuePod& result, const IDateBuilder&) {
  2665. const auto start = it;
  2666. size_t cnt = 0U;
  2667. while (limit > 0 && cnt < size && std::isalpha(*it)) {
  2668. ++it;
  2669. ++cnt;
  2670. --limit;
  2671. }
  2672. const std::string_view monthName{start, cnt};
  2673. ui8 month = 0U;
  2674. if (cnt < size || !ValidateMonthShortName(monthName, month)) {
  2675. return false;
  2676. }
  2677. SetMonth<TResourceName>(result, month);
  2678. return true;
  2679. });
  2680. break;
  2681. }
  2682. case 'B': {
  2683. Scanners_.emplace_back([](std::string_view::const_iterator& it, size_t limit, TUnboxedValuePod& result, const IDateBuilder&) {
  2684. const auto start = it;
  2685. size_t cnt = 0U;
  2686. while (limit > 0 && std::isalpha(*it)) {
  2687. ++it;
  2688. ++cnt;
  2689. --limit;
  2690. }
  2691. const std::string_view monthName{start, cnt};
  2692. ui8 month = 0U;
  2693. if (!ValidateMonthFullName(monthName, month)) {
  2694. return false;
  2695. }
  2696. SetMonth<TResourceName>(result, month);
  2697. return true;
  2698. });
  2699. break;
  2700. }
  2701. default:
  2702. ythrow yexception() << "invalid format character: " << *ptr;
  2703. }
  2704. dataStart = ptr + 1U;
  2705. }
  2706. if (dataSize) {
  2707. Scanners_.emplace_back(TDataScanner{std::string_view(&*dataStart, dataSize)});
  2708. }
  2709. }
  2710. };
  2711. #define PARSE_SPECIFIC_FORMAT(format) \
  2712. SIMPLE_STRICT_UDF(TParse##format, TOptional<TResource<TMResourceName>>(TAutoMap<char*>)) { \
  2713. auto str = args[0].AsStringRef(); \
  2714. TInstant instant; \
  2715. if (!TInstant::TryParse##format(TStringBuf(str.Data(), str.Size()), instant) || instant.Seconds() >= NUdf::MAX_DATETIME) { \
  2716. return TUnboxedValuePod(); \
  2717. } \
  2718. auto& builder = valueBuilder->GetDateBuilder(); \
  2719. TUnboxedValuePod result(0); \
  2720. auto& storage = Reference(result); \
  2721. storage.FromTimestamp(builder, instant.MicroSeconds()); \
  2722. return result; \
  2723. }
  2724. PARSE_SPECIFIC_FORMAT(Rfc822);
  2725. PARSE_SPECIFIC_FORMAT(Iso8601);
  2726. PARSE_SPECIFIC_FORMAT(Http);
  2727. PARSE_SPECIFIC_FORMAT(X509);
  2728. SIMPLE_MODULE(TDateTime2Module,
  2729. TUserDataTypeFuncFactory<true, true, SplitUDF, TSplit,
  2730. TDate,
  2731. TDatetime,
  2732. TTimestamp,
  2733. TTzDate,
  2734. TTzDatetime,
  2735. TTzTimestamp,
  2736. TDate32,
  2737. TDatetime64,
  2738. TTimestamp64>,
  2739. TMakeDate,
  2740. TMakeDatetime,
  2741. TMakeTimestamp,
  2742. TMakeTzDate,
  2743. TMakeTzDatetime,
  2744. TMakeTzTimestamp,
  2745. TConvert,
  2746. TMakeDate32,
  2747. TMakeDatetime64,
  2748. TMakeTimestamp64,
  2749. TGetDateComponent<GetYearUDF, ui16, GetYear<TMResourceName>, i32, GetYear<TM64ResourceName>>,
  2750. TGetDateComponent<GetDayOfYearUDF, ui16, GetDayOfYear<TMResourceName>, ui16, GetDayOfYear<TM64ResourceName>>,
  2751. TGetDateComponent<GetMonthUDF, ui8, GetMonth<TMResourceName>, ui8, GetMonth<TM64ResourceName>>,
  2752. TGetDateComponentName<GetMonthNameUDF, GetMonthName<TMResourceName>, GetMonthName<TM64ResourceName>>,
  2753. TGetDateComponent<GetWeekOfYearUDF, ui8, GetWeekOfYear<TMResourceName>, ui8, GetWeekOfYear<TM64ResourceName>>,
  2754. TGetDateComponent<GetWeekOfYearIso8601UDF, ui8, GetWeekOfYearIso8601<TMResourceName>, ui8, GetWeekOfYearIso8601<TM64ResourceName>>,
  2755. TGetDateComponent<GetDayOfMonthUDF, ui8, GetDay<TMResourceName>, ui8, GetDay<TM64ResourceName>>,
  2756. TGetDateComponent<GetDayOfWeekUDF, ui8, GetDayOfWeek<TMResourceName>, ui8, GetDayOfWeek<TM64ResourceName>>,
  2757. TGetDateComponentName<GetDayOfWeekNameUDF, GetDayOfWeekName<TMResourceName>, GetDayOfWeekName<TM64ResourceName>>,
  2758. TGetTimeComponent<GetHourUDF, ui8, GetHour<TMResourceName>, GetHour<TM64ResourceName>, 1u, 3600u, 24u, false>,
  2759. TGetTimeComponent<GetMinuteUDF, ui8, GetMinute<TMResourceName>, GetMinute<TM64ResourceName>, 1u, 60u, 60u, false>,
  2760. TGetTimeComponent<GetSecondUDF, ui8, GetSecond<TMResourceName>, GetSecond<TM64ResourceName>, 1u, 1u, 60u, false>,
  2761. TGetTimeComponent<GetMillisecondOfSecondUDF, ui32, GetMicrosecond<TMResourceName>, GetMicrosecond<TM64ResourceName>, 1000u, 1000u, 1000u, true>,
  2762. TGetTimeComponent<GetMicrosecondOfSecondUDF, ui32, GetMicrosecond<TMResourceName>, GetMicrosecond<TM64ResourceName>, 1u, 1u, 1000000u, true>,
  2763. TGetDateComponent<GetTimezoneIdUDF, ui16, GetTimezoneId<TMResourceName>, ui16, GetTimezoneId<TM64ResourceName>>,
  2764. TGetDateComponentName<GetTimezoneNameUDF, GetTimezoneName<TMResourceName>, GetTimezoneName<TM64ResourceName>>,
  2765. TUpdate,
  2766. TFromSeconds,
  2767. TFromMilliseconds,
  2768. TFromMicroseconds,
  2769. TFromSeconds64,
  2770. TFromMilliseconds64,
  2771. TFromMicroseconds64,
  2772. TIntervalFromDays,
  2773. TIntervalFromHours,
  2774. TIntervalFromMinutes,
  2775. TIntervalFromSeconds,
  2776. TIntervalFromMilliseconds,
  2777. TIntervalFromMicroseconds,
  2778. TInterval64FromDays,
  2779. TInterval64FromHours,
  2780. TInterval64FromMinutes,
  2781. TInterval64FromSeconds,
  2782. TInterval64FromMilliseconds,
  2783. TInterval64FromMicroseconds,
  2784. TToDays,
  2785. TToHours,
  2786. TToMinutes,
  2787. TBoundaryOf<StartOfYearUDF, SimpleDatetimeToDatetimeUdf<TMResourceName, StartOfYear<TTMStorage>>,
  2788. SimpleDatetimeToDatetimeUdf<TM64ResourceName, StartOfYear<TTM64Storage>>>,
  2789. TBoundaryOf<StartOfQuarterUDF, SimpleDatetimeToDatetimeUdf<TMResourceName, StartOfQuarter<TTMStorage>>,
  2790. SimpleDatetimeToDatetimeUdf<TM64ResourceName, StartOfQuarter<TTM64Storage>>>,
  2791. TBoundaryOf<StartOfMonthUDF, SimpleDatetimeToDatetimeUdf<TMResourceName, StartOfMonth<TTMStorage>>,
  2792. SimpleDatetimeToDatetimeUdf<TM64ResourceName, StartOfMonth<TTM64Storage>>>,
  2793. TBoundaryOf<StartOfWeekUDF, SimpleDatetimeToDatetimeUdf<TMResourceName, StartOfWeek<TTMStorage>>,
  2794. SimpleDatetimeToDatetimeUdf<TM64ResourceName, StartOfWeek<TTM64Storage>>>,
  2795. TBoundaryOf<StartOfDayUDF, SimpleDatetimeToDatetimeUdf<TMResourceName, StartOfDay<TTMStorage>>,
  2796. SimpleDatetimeToDatetimeUdf<TM64ResourceName, StartOfDay<TTM64Storage>>>,
  2797. TBoundaryOfInterval<StartOfUDF, SimpleDatetimeToIntervalUdf<TMResourceName, StartOf<TTMStorage>>,
  2798. SimpleDatetimeToIntervalUdf<TM64ResourceName, StartOf<TTM64Storage>>>,
  2799. TTimeOfDay,
  2800. TShift<ShiftYearsUDF, DoAddYears<TMResourceName>, DoAddYears<TM64ResourceName>>,
  2801. TShift<ShiftQuartersUDF, DoAddQuarters<TMResourceName>, DoAddQuarters<TM64ResourceName>>,
  2802. TShift<ShiftMonthsUDF, DoAddMonths<TMResourceName>, DoAddMonths<TM64ResourceName>>,
  2803. TBoundaryOf<EndOfYearUDF, SimpleDatetimeToDatetimeUdf<TMResourceName, EndOfYear<TTMStorage>>,
  2804. SimpleDatetimeToDatetimeUdf<TM64ResourceName, EndOfYear<TTM64Storage>>>,
  2805. TBoundaryOf<EndOfQuarterUDF, SimpleDatetimeToDatetimeUdf<TMResourceName, EndOfQuarter<TTMStorage>>,
  2806. SimpleDatetimeToDatetimeUdf<TM64ResourceName, EndOfQuarter<TTM64Storage>>>,
  2807. TBoundaryOf<EndOfMonthUDF, SimpleDatetimeToDatetimeUdf<TMResourceName, EndOfMonth<TTMStorage>>,
  2808. SimpleDatetimeToDatetimeUdf<TM64ResourceName, EndOfMonth<TTM64Storage>>>,
  2809. TBoundaryOf<EndOfWeekUDF, SimpleDatetimeToDatetimeUdf<TMResourceName, EndOfWeek<TTMStorage>>,
  2810. SimpleDatetimeToDatetimeUdf<TM64ResourceName, EndOfWeek<TTM64Storage>>>,
  2811. TBoundaryOf<EndOfDayUDF, SimpleDatetimeToDatetimeUdf<TMResourceName, EndOfDay<TTMStorage>>,
  2812. SimpleDatetimeToDatetimeUdf<TM64ResourceName, EndOfDay<TTM64Storage>>>,
  2813. TBoundaryOfInterval<EndOfUDF, SimpleDatetimeToIntervalUdf<TMResourceName, EndOf<TTMStorage>>,
  2814. SimpleDatetimeToIntervalUdf<TM64ResourceName, EndOf<TTM64Storage>>>,
  2815. TToUnits<ToSecondsUDF, ui32, 1>,
  2816. TToUnits<ToMillisecondsUDF, ui64, 1000>,
  2817. TToUnits<ToMicrosecondsUDF, ui64, 1000000>,
  2818. TFormat,
  2819. TParse<ParseUDF, TMResourceName>,
  2820. TParse<Parse64UDF, TM64ResourceName>,
  2821. TParseRfc822,
  2822. TParseIso8601,
  2823. TParseHttp,
  2824. TParseX509
  2825. )
  2826. }
  2827. REGISTER_MODULES(TDateTime2Module)