@@ -512,8 +512,16 @@ TValue DoAddYears(const TValue& date, i64 years, const NUdf::IDateBuilder& build
512512#undef ACCESSORS
513513#undef ACCESSORS_POLY
514514
515- inline bool ValidateYear (ui16 year) {
516- return year >= NUdf::MIN_YEAR - 1 || year <= NUdf::MAX_YEAR + 1 ;
515+ // FIXME: The default value for TResourceName allows to omit
516+ // explicit specialization in functions that still doesn't support
517+ // big datetime types. Should be removed in future.
518+ template <const char * TResourceName = TMResourceName>
519+ inline bool ValidateYear (std::conditional_t <TResourceName == TMResourceName, ui16, i32 > year) {
520+ if constexpr (TResourceName == TMResourceName) {
521+ return year >= NUdf::MIN_YEAR || year < NUdf::MAX_YEAR;
522+ } else {
523+ return year >= NUdf::MIN_YEAR32 || year < NUdf::MAX_YEAR32;
524+ }
517525 }
518526
519527 inline bool ValidateMonth (ui8 month) {
@@ -1412,125 +1420,196 @@ TUnboxedValue GetTimezoneName(const IValueBuilder* valueBuilder, const TUnboxedV
14121420 // Update
14131421
14141422 class TUpdate : public TBoxedValue {
1415- const TSourcePosition Pos_;
14161423 public:
1417- explicit TUpdate (TSourcePosition pos)
1418- : Pos_(pos)
1419- {}
1420-
1421- TUnboxedValue Run (
1422- const IValueBuilder* valueBuilder,
1423- const TUnboxedValuePod* args) const override
1424- {
1425- try {
1426- EMPTY_RESULT_ON_EMPTY_ARG (0 );
1427- auto result = args[0 ];
1428-
1429- if (args[1 ]) {
1430- auto year = args[1 ].Get <ui16>();
1431- if (!ValidateYear (year)) {
1432- return TUnboxedValuePod ();
1433- }
1434- SetYear (result, year);
1435- }
1436- if (args[2 ]) {
1437- auto month = args[2 ].Get <ui8>();
1438- if (!ValidateMonth (month)) {
1439- return TUnboxedValuePod ();
1440- }
1441- SetMonth (result, month);
1442- }
1443- if (args[3 ]) {
1444- auto day = args[3 ].Get <ui8>();
1445- if (!ValidateDay (day)) {
1446- return TUnboxedValuePod ();
1447- }
1448- SetDay (result, day);
1449- }
1450- if (args[4 ]) {
1451- auto hour = args[4 ].Get <ui8>();
1452- if (!ValidateHour (hour)) {
1453- return TUnboxedValuePod ();
1454- }
1455- SetHour (result, hour);
1456- }
1457- if (args[5 ]) {
1458- auto minute = args[5 ].Get <ui8>();
1459- if (!ValidateMinute (minute)) {
1460- return TUnboxedValuePod ();
1461- }
1462- SetMinute (result, minute);
1463- }
1464- if (args[6 ]) {
1465- auto second = args[6 ].Get <ui8>();
1466- if (!ValidateSecond (second)) {
1467- return TUnboxedValuePod ();
1468- }
1469- SetSecond (result, second);
1470- }
1471- if (args[7 ]) {
1472- auto microsecond = args[7 ].Get <ui32>();
1473- if (!ValidateMicrosecond (microsecond)) {
1474- return TUnboxedValuePod ();
1475- }
1476- SetMicrosecond (result, microsecond);
1477- }
1478- if (args[8 ]) {
1479- auto timezoneId = args[8 ].Get <ui16>();
1480- if (!ValidateTimezoneId (timezoneId)) {
1481- return TUnboxedValuePod ();
1482- }
1483- SetTimezoneId (result, timezoneId);
1484- }
1485-
1486- auto & builder = valueBuilder->GetDateBuilder ();
1487- auto & storage = Reference (result);
1488- if (!storage.Validate (builder)) {
1489- return TUnboxedValuePod ();
1490- }
1491- return result;
1492- } catch (const std::exception& e) {
1493- UdfTerminate ((TStringBuilder () << Pos_ << " " << e.what ()).data ());
1494- }
1495- }
1496-
1424+ typedef bool TTypeAwareMarker;
14971425 static const TStringRef& Name () {
14981426 static auto name = TStringRef::Of (" Update" );
14991427 return name;
15001428 }
15011429
15021430 static bool DeclareSignature (
15031431 const TStringRef& name,
1504- TType*,
1432+ TType* userType ,
15051433 IFunctionTypeInfoBuilder& builder,
15061434 bool typesOnly)
15071435 {
15081436 if (Name () != name) {
15091437 return false ;
15101438 }
15111439
1512- auto resourceType = builder.Resource (TMResourceName);
1513- auto optionalResourceType = builder.Optional ()->Item (resourceType).Build ();
1440+ if (!userType) {
1441+ builder.SetError (" User type is missing" );
1442+ return true ;
1443+ }
15141444
1515- builder.OptionalArgs (8 ).Args ()->Add (resourceType).Flags (ICallablePayload::TArgumentFlags::AutoMap)
1516- .Add (builder.Optional ()->Item <ui16>().Build ()).Name (" Year" )
1517- .Add (builder.Optional ()->Item <ui8>().Build ()).Name (" Month" )
1518- .Add (builder.Optional ()->Item <ui8>().Build ()).Name (" Day" )
1519- .Add (builder.Optional ()->Item <ui8>().Build ()).Name (" Hour" )
1520- .Add (builder.Optional ()->Item <ui8>().Build ()).Name (" Minute" )
1521- .Add (builder.Optional ()->Item <ui8>().Build ()).Name (" Second" )
1522- .Add (builder.Optional ()->Item <ui32>().Build ()).Name (" Microsecond" )
1523- .Add (builder.Optional ()->Item <ui16>().Build ()).Name (" TimezoneId" );
1445+ builder.UserType (userType);
15241446
1525- builder.Returns (optionalResourceType);
1447+ const auto typeInfoHelper = builder.TypeInfoHelper ();
1448+ TTupleTypeInspector tuple (*typeInfoHelper, userType);
1449+ Y_ENSURE (tuple, " Tuple with args and options tuples expected" );
1450+ Y_ENSURE (tuple.GetElementsCount () > 0 ,
1451+ " Tuple has to contain positional arguments" );
15261452
1527- if (!typesOnly) {
1528- builder.Implementation (new TUpdate (builder.GetSourcePosition ()));
1453+ TTupleTypeInspector argsTuple (*typeInfoHelper, tuple.GetElementType (0 ));
1454+ Y_ENSURE (argsTuple, " Tuple with args expected" );
1455+ if (argsTuple.GetElementsCount () == 0 ) {
1456+ builder.SetError (" At least one argument expected" );
1457+ return true ;
15291458 }
15301459
1531- builder.IsStrict ();
1460+ auto argType = argsTuple.GetElementType (0 );
1461+
1462+ if (const auto optType = TOptionalTypeInspector (*typeInfoHelper, argType)) {
1463+ argType = optType.GetItemType ();
1464+ }
1465+
1466+ TResourceTypeInspector resource (*typeInfoHelper, argType);
1467+ if (!resource) {
1468+ TDataTypeInspector data (*typeInfoHelper, argType);
1469+ if (!data) {
1470+ SetInvalidTypeError (builder, typeInfoHelper, argType);
1471+ return true ;
1472+ }
1473+
1474+ const auto features = NUdf::GetDataTypeInfo (NUdf::GetDataSlot (data.GetTypeId ())).Features ;
1475+ if (features & NUdf::BigDateType) {
1476+ BuildSignature<TM64ResourceName>(builder, typesOnly);
1477+ return true ;
1478+ }
1479+ if (features & (NUdf::DateType | NUdf::TzDateType)) {
1480+ BuildSignature<TMResourceName>(builder, typesOnly);
1481+ return true ;
1482+ }
1483+
1484+ SetInvalidTypeError (builder, typeInfoHelper, argType);
1485+ return true ;
1486+ }
1487+
1488+ if (resource.GetTag () == TStringRef::Of (TM64ResourceName)) {
1489+ BuildSignature<TM64ResourceName>(builder, typesOnly);
1490+ return true ;
1491+ }
1492+
1493+ if (resource.GetTag () == TStringRef::Of (TMResourceName)) {
1494+ BuildSignature<TMResourceName>(builder, typesOnly);
1495+ return true ;
1496+ }
1497+
1498+ ::TStringBuilder sb;
1499+ sb << " Unexpected Resource tag: got '" << resource.GetTag () << " '" ;
1500+ builder.SetError (sb);
15321501 return true ;
15331502 }
1503+ private:
1504+ template <const char * TResourceName>
1505+ class TImpl : public TBoxedValue {
1506+ public:
1507+ TUnboxedValue Run (const IValueBuilder* valueBuilder, const TUnboxedValuePod* args) const final {
1508+ try {
1509+ EMPTY_RESULT_ON_EMPTY_ARG (0 );
1510+ auto result = args[0 ];
1511+
1512+ if (args[1 ]) {
1513+ auto year = args[1 ].Get <std::conditional_t <TResourceName == TMResourceName, ui16, i32 >>();
1514+ if (!ValidateYear<TResourceName>(year)) {
1515+ return TUnboxedValuePod ();
1516+ }
1517+ SetYear<TResourceName>(result, year);
1518+ }
1519+ if (args[2 ]) {
1520+ auto month = args[2 ].Get <ui8>();
1521+ if (!ValidateMonth (month)) {
1522+ return TUnboxedValuePod ();
1523+ }
1524+ SetMonth<TResourceName>(result, month);
1525+ }
1526+ if (args[3 ]) {
1527+ auto day = args[3 ].Get <ui8>();
1528+ if (!ValidateDay (day)) {
1529+ return TUnboxedValuePod ();
1530+ }
1531+ SetDay<TResourceName>(result, day);
1532+ }
1533+ if (args[4 ]) {
1534+ auto hour = args[4 ].Get <ui8>();
1535+ if (!ValidateHour (hour)) {
1536+ return TUnboxedValuePod ();
1537+ }
1538+ SetHour<TResourceName>(result, hour);
1539+ }
1540+ if (args[5 ]) {
1541+ auto minute = args[5 ].Get <ui8>();
1542+ if (!ValidateMinute (minute)) {
1543+ return TUnboxedValuePod ();
1544+ }
1545+ SetMinute<TResourceName>(result, minute);
1546+ }
1547+ if (args[6 ]) {
1548+ auto second = args[6 ].Get <ui8>();
1549+ if (!ValidateSecond (second)) {
1550+ return TUnboxedValuePod ();
1551+ }
1552+ SetSecond<TResourceName>(result, second);
1553+ }
1554+ if (args[7 ]) {
1555+ auto microsecond = args[7 ].Get <ui32>();
1556+ if (!ValidateMicrosecond (microsecond)) {
1557+ return TUnboxedValuePod ();
1558+ }
1559+ SetMicrosecond<TResourceName>(result, microsecond);
1560+ }
1561+ if (args[8 ]) {
1562+ auto timezoneId = args[8 ].Get <ui16>();
1563+ if (!ValidateTimezoneId (timezoneId)) {
1564+ return TUnboxedValuePod ();
1565+ }
1566+ SetTimezoneId<TResourceName>(result, timezoneId);
1567+ }
1568+
1569+ auto & builder = valueBuilder->GetDateBuilder ();
1570+ auto & storage = Reference<TResourceName>(result);
1571+ if (!storage.Validate (builder)) {
1572+ return TUnboxedValuePod ();
1573+ }
1574+ return result;
1575+ } catch (const std::exception& e) {
1576+ TStringBuilder sb;
1577+ sb << CurrentExceptionMessage ();
1578+ sb << Endl << " [" << TStringBuf (Name ()) << " ]" ;
1579+ UdfTerminate (sb.c_str ());
1580+ }
1581+ }
1582+
1583+ };
1584+
1585+ static void SetInvalidTypeError (NUdf::IFunctionTypeInfoBuilder& builder,
1586+ ITypeInfoHelper::TPtr typeInfoHelper, const TType* argType)
1587+ {
1588+ ::TStringBuilder sb;
1589+ sb << " Invalid argument type: got " ;
1590+ TTypePrinter (*typeInfoHelper, argType).Out (sb.Out );
1591+ sb << " , but Resource<" << TMResourceName <<" > or Resource<"
1592+ << TM64ResourceName << " > expected" ;
1593+ builder.SetError (sb);
1594+ }
1595+
1596+ template <const char * TResourceName>
1597+ static void BuildSignature (NUdf::IFunctionTypeInfoBuilder& builder, bool typesOnly) {
1598+ builder.Returns <TOptional<TResource<TResourceName>>>();
1599+ builder.OptionalArgs (8 ).Args ()->Add <TAutoMap<TResource<TResourceName>>>()
1600+ .template Add <TOptional<std::conditional_t <TResourceName == TMResourceName, ui16, i32 >>>().Name (" Year" )
1601+ .template Add <TOptional<ui8>>().Name (" Month" )
1602+ .template Add <TOptional<ui8>>().Name (" Day" )
1603+ .template Add <TOptional<ui8>>().Name (" Hour" )
1604+ .template Add <TOptional<ui8>>().Name (" Minute" )
1605+ .template Add <TOptional<ui8>>().Name (" Second" )
1606+ .template Add <TOptional<ui32>>().Name (" Microsecond" )
1607+ .template Add <TOptional<ui16>>().Name (" TimezoneId" );
1608+ builder.IsStrict ();
1609+ if (!typesOnly) {
1610+ builder.Implementation (new TImpl<TResourceName>());
1611+ }
1612+ }
15341613 };
15351614
15361615 // From*
0 commit comments