@@ -512,8 +512,16 @@ TValue DoAddYears(const TValue& date, i64 years, const NUdf::IDateBuilder& build
512
512
#undef ACCESSORS
513
513
#undef ACCESSORS_POLY
514
514
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
+ }
517
525
}
518
526
519
527
inline bool ValidateMonth (ui8 month) {
@@ -1412,125 +1420,196 @@ TUnboxedValue GetTimezoneName(const IValueBuilder* valueBuilder, const TUnboxedV
1412
1420
// Update
1413
1421
1414
1422
class TUpdate : public TBoxedValue {
1415
- const TSourcePosition Pos_;
1416
1423
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;
1497
1425
static const TStringRef& Name () {
1498
1426
static auto name = TStringRef::Of (" Update" );
1499
1427
return name;
1500
1428
}
1501
1429
1502
1430
static bool DeclareSignature (
1503
1431
const TStringRef& name,
1504
- TType*,
1432
+ TType* userType ,
1505
1433
IFunctionTypeInfoBuilder& builder,
1506
1434
bool typesOnly)
1507
1435
{
1508
1436
if (Name () != name) {
1509
1437
return false ;
1510
1438
}
1511
1439
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
+ }
1514
1444
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);
1524
1446
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" );
1526
1452
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 ;
1529
1458
}
1530
1459
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);
1532
1501
return true ;
1533
1502
}
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
+ }
1534
1613
};
1535
1614
1536
1615
// From*
0 commit comments