Skip to content

Commit add9063

Browse files
committed
YQL-18303: Introduce Update overload
commit_hash:3afbcdd00ad47ecf35cb29bb25a5d7658ed1d5cb
1 parent 92ee8c5 commit add9063

File tree

11 files changed

+1879
-299
lines changed

11 files changed

+1879
-299
lines changed

yql/essentials/udfs/common/datetime2/datetime_udf.cpp

Lines changed: 178 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)