datetime_udf.cpp 111 KB

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