datetime_udf.cpp 137 KB

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