8
8
#include < yql/essentials/minikql/mkql_node_printer.h>
9
9
#include < yql/essentials/minikql/mkql_type_builder.h>
10
10
#include < yql/essentials/minikql/mkql_utils.h>
11
+ #include < yql/essentials/minikql/datetime/datetime64.h>
11
12
#include < yql/essentials/utils/yql_panic.h>
12
13
13
14
#include < library/cpp/containers/stack_array/stack_array.h>
@@ -27,6 +28,46 @@ TString TruncateTypeDiff(const TString& s) {
27
28
return s.substr (0 ,TypeDiffLimit) + " ..." ;
28
29
}
29
30
31
+ static const char TMResourceName[] = " DateTime2.TM" ;
32
+ static const char TM64ResourceName[] = " DateTime2.TM64" ;
33
+ // XXX: This class implements the wrapper to properly handle the
34
+ // case when the signature of the emitted callable (i.e. callable
35
+ // type) requires the extended datetime resource as an argument,
36
+ // but the basic one is given. It wraps the unboxed value with
37
+ // the closure to add the bridge with the implicit datetime
38
+ // resource conversion.
39
+ class TDateTimeConvertWrapper : public NUdf ::TBoxedValue {
40
+ public:
41
+ TDateTimeConvertWrapper (NUdf::TUnboxedValue&& callable)
42
+ : Callable_(callable)
43
+ {};
44
+
45
+ private:
46
+ NUdf::TUnboxedValue Run (const NUdf::IValueBuilder* valueBuilder, const NUdf::TUnboxedValuePod* args) const final {
47
+ return NUdf::TUnboxedValuePod (new TDateTimeConverter (Callable_.Run (valueBuilder, args)));
48
+ }
49
+
50
+ class TDateTimeConverter : public NUdf ::TBoxedValue {
51
+ public:
52
+ TDateTimeConverter (NUdf::TUnboxedValue&& closure)
53
+ : Closure_(closure)
54
+ {}
55
+ private:
56
+ NUdf::TUnboxedValue Run (const NUdf::IValueBuilder* valueBuilder, const NUdf::TUnboxedValuePod* args) const final {
57
+ NUdf::TUnboxedValuePod newArg;
58
+ const auto arg = args[0 ];
59
+ const auto & narrow = *reinterpret_cast <const NYql::DateTime::TTMStorage*>(arg.GetRawPtr ());
60
+ auto & extended = *reinterpret_cast <NYql::DateTime::TTM64Storage*>(newArg.GetRawPtr ());
61
+ extended.From (narrow);
62
+ return Closure_.Run (valueBuilder, &newArg);
63
+ }
64
+
65
+ const NUdf::TUnboxedValue Closure_;
66
+ };
67
+
68
+ const NUdf::TUnboxedValue Callable_;
69
+ };
70
+
30
71
template <class TValidatePolicy , class TValidateMode >
31
72
class TSimpleUdfWrapper : public TMutableComputationNode <TSimpleUdfWrapper<TValidatePolicy,TValidateMode>> {
32
73
using TBaseComputation = TMutableComputationNode<TSimpleUdfWrapper<TValidatePolicy,TValidateMode>>;
@@ -38,14 +79,16 @@ using TBaseComputation = TMutableComputationNode<TSimpleUdfWrapper<TValidatePoli
38
79
NUdf::TSourcePosition pos,
39
80
const TCallableType* callableType,
40
81
const TCallableType* functionType,
41
- TType* userType)
82
+ TType* userType,
83
+ bool wrapDateTimeConvert)
42
84
: TBaseComputation(mutables, EValueRepresentation::Boxed)
43
85
, FunctionName(std::move(functionName))
44
86
, TypeConfig(std::move(typeConfig))
45
87
, Pos(pos)
46
88
, CallableType(callableType)
47
89
, FunctionType(functionType)
48
90
, UserType(userType)
91
+ , WrapDateTimeConvert(wrapDateTimeConvert)
49
92
{
50
93
this ->Stateless = false ;
51
94
}
@@ -62,6 +105,7 @@ using TBaseComputation = TMutableComputationNode<TSimpleUdfWrapper<TValidatePoli
62
105
NUdf::TUnboxedValue udf (NUdf::TUnboxedValuePod (funcInfo.Implementation .Release ()));
63
106
TValidate<TValidatePolicy,TValidateMode>::WrapCallable (FunctionType, udf, TStringBuilder () << " FunctionWithConfig<" << FunctionName << " >" );
64
107
ExtendArgs (udf, CallableType, funcInfo.FunctionType );
108
+ ConvertDateTimeArg (udf);
65
109
return udf.Release ();
66
110
}
67
111
private:
@@ -102,6 +146,12 @@ using TBaseComputation = TMutableComputationNode<TSimpleUdfWrapper<TValidatePoli
102
146
}
103
147
}
104
148
149
+ void ConvertDateTimeArg (NUdf::TUnboxedValue& callable) const {
150
+ if (WrapDateTimeConvert) {
151
+ callable = NUdf::TUnboxedValuePod (new TDateTimeConvertWrapper (std::move (callable)));
152
+ }
153
+ }
154
+
105
155
void RegisterDependencies () const final {}
106
156
107
157
const TString FunctionName;
@@ -110,6 +160,7 @@ using TBaseComputation = TMutableComputationNode<TSimpleUdfWrapper<TValidatePoli
110
160
const TCallableType *const CallableType;
111
161
const TCallableType *const FunctionType;
112
162
TType *const UserType;
163
+ bool WrapDateTimeConvert;
113
164
};
114
165
115
166
class TUdfRunCodegeneratorNode : public TSimpleUdfWrapper <TValidateErrorPolicyNone, TValidateModeLazy<TValidateErrorPolicyNone>>
@@ -126,11 +177,12 @@ class TUdfRunCodegeneratorNode: public TSimpleUdfWrapper<TValidateErrorPolicyNon
126
177
const TCallableType* callableType,
127
178
const TCallableType* functionType,
128
179
TType* userType,
180
+ bool wrapDateTimeConvert,
129
181
TString&& moduleIRUniqID,
130
182
TString&& moduleIR,
131
183
TString&& fuctioNameIR,
132
184
NUdf::TUniquePtr<NUdf::IBoxedValue>&& impl)
133
- : TSimpleUdfWrapper(mutables, std::move(functionName), std::move(typeConfig), pos, callableType, functionType, userType)
185
+ : TSimpleUdfWrapper(mutables, std::move(functionName), std::move(typeConfig), pos, callableType, functionType, userType, wrapDateTimeConvert )
134
186
, ModuleIRUniqID(std::move(moduleIRUniqID))
135
187
, ModuleIR(std::move(moduleIR))
136
188
, IRFunctionName(std::move(fuctioNameIR))
@@ -174,7 +226,8 @@ using TBaseComputation = TMutableCodegeneratorPtrNode<TUdfWrapper<TValidatePolic
174
226
IComputationNode* runConfigNode,
175
227
ui32 runConfigArgs,
176
228
const TCallableType* callableType,
177
- TType* userType)
229
+ TType* userType,
230
+ bool wrapDateTimeConvert)
178
231
: TBaseComputation(mutables, EValueRepresentation::Boxed)
179
232
, FunctionName(std::move(functionName))
180
233
, TypeConfig(std::move(typeConfig))
@@ -183,6 +236,7 @@ using TBaseComputation = TMutableCodegeneratorPtrNode<TUdfWrapper<TValidatePolic
183
236
, RunConfigArgs(runConfigArgs)
184
237
, CallableType(callableType)
185
238
, UserType(userType)
239
+ , WrapDateTimeConvert(wrapDateTimeConvert)
186
240
, UdfIndex(mutables.CurValueIndex++)
187
241
{
188
242
this ->Stateless = false ;
@@ -193,6 +247,7 @@ using TBaseComputation = TMutableCodegeneratorPtrNode<TUdfWrapper<TValidatePolic
193
247
if (!udf.HasValue ()) {
194
248
MakeUdf (ctx, udf);
195
249
}
250
+ ConvertDateTimeArg (udf);
196
251
NStackArray::TStackArray<NUdf::TUnboxedValue> args (ALLOC_ON_STACK (NUdf::TUnboxedValue, RunConfigArgs));
197
252
args[0 ] = RunConfigNode->GetValue (ctx);
198
253
auto callable = udf.Run (ctx.Builder , args.data ());
@@ -226,6 +281,11 @@ using TBaseComputation = TMutableCodegeneratorPtrNode<TUdfWrapper<TValidatePolic
226
281
227
282
block = main;
228
283
284
+ const auto convertFunc = ConstantInt::get (Type::getInt64Ty (context), GetMethodPtr (&TUdfWrapper::ConvertDateTimeArg));
285
+ const auto convertType = FunctionType::get (Type::getVoidTy (context), {self->getType (), udfPtr->getType ()}, false );
286
+ const auto convertFuncPtr = CastInst::Create (Instruction::IntToPtr, convertFunc, PointerType::getUnqual (convertType), " convert" , block);
287
+ CallInst::Create (convertType, convertFuncPtr, {self, udfPtr}, " " , block);
288
+
229
289
const auto argsType = ArrayType::get (valueType, RunConfigArgs);
230
290
const auto args = new AllocaInst (argsType, 0U , " args" , block);
231
291
const auto zero = ConstantInt::get (indexType, 0 );
@@ -270,6 +330,12 @@ using TBaseComputation = TMutableCodegeneratorPtrNode<TUdfWrapper<TValidatePolic
270
330
TValidate<TValidatePolicy,TValidateMode>::WrapCallable (CallableType, callable, TStringBuilder () << " FunctionWithConfig<" << FunctionName << " >" );
271
331
}
272
332
333
+ void ConvertDateTimeArg (NUdf::TUnboxedValue& callable) const {
334
+ if (WrapDateTimeConvert) {
335
+ callable = NUdf::TUnboxedValuePod (new TDateTimeConvertWrapper (std::move (callable)));
336
+ }
337
+ }
338
+
273
339
void RegisterDependencies () const final {
274
340
this ->DependsOn (RunConfigNode);
275
341
}
@@ -281,6 +347,7 @@ using TBaseComputation = TMutableCodegeneratorPtrNode<TUdfWrapper<TValidatePolic
281
347
const ui32 RunConfigArgs;
282
348
const TCallableType* CallableType;
283
349
TType* const UserType;
350
+ bool WrapDateTimeConvert;
284
351
const ui32 UdfIndex;
285
352
};
286
353
@@ -310,6 +377,63 @@ inline IComputationNode* CreateUdfWrapper(const TComputationNodeFactoryContext&
310
377
};
311
378
}
312
379
380
+ // XXX: The helper below allows to make a stitchless upgrade
381
+ // of MKQL runtime, regarding the incompatible changes made for
382
+ // DateTime::Format UDF.
383
+ template <bool Extended>
384
+ static bool IsDateTimeResource (const TType* type) {
385
+ if (!type->IsResource ()) {
386
+ return false ;
387
+ }
388
+ const auto resourceName = AS_TYPE (TResourceType, type)->GetTag ();
389
+
390
+ if constexpr (Extended) {
391
+ return resourceName == NUdf::TStringRef::Of (TM64ResourceName);
392
+ } else {
393
+ return resourceName == NUdf::TStringRef::Of (TMResourceName);
394
+ }
395
+ }
396
+
397
+ static bool IsDateTimeConvertible (const NUdf::TStringRef& funcName,
398
+ const TCallableType* nodeType,
399
+ const TCallableType* funcType,
400
+ bool & needConvert)
401
+ {
402
+ Y_DEBUG_ABORT_UNLESS (!needConvert);
403
+ if (funcName == NUdf::TStringRef::Of (" DateTime2.Format" )) {
404
+ Y_DEBUG_ABORT_UNLESS (nodeType->GetArgumentsCount ());
405
+ Y_DEBUG_ABORT_UNLESS (funcType->GetArgumentsCount ());
406
+ // XXX: In general, DateTime resources are not convertible
407
+ // in runtime, but for the stitchless upgrade of MKQL
408
+ // runtime, we consider the basic resource, being
409
+ // convertible to the extended one for DateTime2.Format...
410
+ if (IsDateTimeResource<false >(nodeType->GetArgumentType (0 )) &&
411
+ IsDateTimeResource<true >(funcType->GetArgumentType (0 )))
412
+ {
413
+ // XXX: ... and to implicitly convert the basic resource
414
+ // to the extended one, the closure has to be wrapped by
415
+ // DateTimeConvertWrapper.
416
+ needConvert = true ;
417
+ return true ;
418
+ }
419
+ }
420
+ if (funcName == NUdf::TStringRef::Of (" DateTime2.Convert" )) {
421
+ // XXX: Vice versa convertion is forbidden as well, but
422
+ // for the stitchless upgrade of MKQL runtime, we consider
423
+ // the extended resource, being compatible with the basic
424
+ // one for the return type of DateTime2.Convert.
425
+ if (IsDateTimeResource<true >(nodeType->GetReturnType ()) &&
426
+ IsDateTimeResource<false >(funcType->GetReturnType ()))
427
+ {
428
+ // XXX: However, DateTime2.Convert has to convert the
429
+ // basic resource to the extended one.
430
+ needConvert = false ;
431
+ return true ;
432
+ }
433
+ }
434
+ return false ;
435
+ }
436
+
313
437
}
314
438
315
439
IComputationNode* WrapUdf (TCallable& callable, const TComputationNodeFactoryContext& ctx) {
@@ -343,6 +467,7 @@ IComputationNode* WrapUdf(TCallable& callable, const TComputationNodeFactoryCont
343
467
344
468
MKQL_ENSURE (status.IsOk (), status.GetError ());
345
469
470
+ bool wrapDateTimeConvert = false ;
346
471
const auto callableFuncType = AS_TYPE (TCallableType, funcInfo.FunctionType );
347
472
const auto callableNodeType = AS_TYPE (TCallableType, callable.GetType ()->GetReturnType ());
348
473
const auto runConfigFuncType = funcInfo.RunConfigType ;
@@ -401,46 +526,59 @@ IComputationNode* WrapUdf(TCallable& callable, const TComputationNodeFactoryCont
401
526
}
402
527
const auto closureFuncType = runConfigNodeType->IsVoid ()
403
528
? callableFuncType
404
- : AS_TYPE (TCallableType, callableFuncType) ->GetReturnType ();
529
+ : AS_TYPE (TCallableType, callableFuncType->GetReturnType () );
405
530
const auto closureNodeType = runConfigNodeType->IsVoid ()
406
- ? AS_TYPE (TCallableType, callableNodeType) ->GetReturnType ()
531
+ ? AS_TYPE (TCallableType, callableNodeType->GetReturnType () )
407
532
: callableNodeType;
408
533
if (!closureNodeType->IsConvertableTo (*closureFuncType)) {
409
- TString diff = TStringBuilder ()
410
- << " type mismatch, expected return type: "
411
- << PrintNode (closureNodeType, true )
412
- << " , actual: "
413
- << PrintNode (closureFuncType, true );
414
- UdfTerminate ((TStringBuilder () << pos
415
- << " Udf Function '"
416
- << funcName
417
- << " ' "
418
- << TruncateTypeDiff (diff)).c_str ());
534
+ if (!IsDateTimeConvertible (funcName, closureNodeType, closureFuncType, wrapDateTimeConvert)) {
535
+ TString diff = TStringBuilder ()
536
+ << " type mismatch, expected return type: "
537
+ << PrintNode (closureNodeType, true )
538
+ << " , actual: "
539
+ << PrintNode (closureFuncType, true );
540
+ UdfTerminate ((TStringBuilder () << pos
541
+ << " Udf Function '"
542
+ << funcName
543
+ << " ' "
544
+ << TruncateTypeDiff (diff)).c_str ());
545
+ }
546
+ MKQL_ENSURE (funcName == NUdf::TStringRef::Of (" DateTime2.Format" ) ||
547
+ funcName == NUdf::TStringRef::Of (" DateTime2.Convert" ),
548
+ " Unexpected function violates the convertible invariants" );
419
549
}
420
550
421
551
const auto runConfigCompNode = LocateNode (ctx.NodeLocator , *runCfgNode.GetNode ());
422
552
const auto runConfigArgs = funcInfo.FunctionType ->GetArgumentsCount ();
423
553
return runConfigNodeType->IsVoid ()
424
- ? CreateUdfWrapper<true >(ctx, std::move (funcName), std::move (typeConfig), pos, callableNodeType, callableFuncType, userType)
425
- : CreateUdfWrapper<false >(ctx, std::move (funcName), std::move (typeConfig), pos, runConfigCompNode, runConfigArgs, callableNodeType, userType);
554
+ ? CreateUdfWrapper<true >(ctx, std::move (funcName), std::move (typeConfig), pos, callableNodeType, callableFuncType, userType, wrapDateTimeConvert)
555
+ : CreateUdfWrapper<false >(ctx, std::move (funcName), std::move (typeConfig), pos, runConfigCompNode, runConfigArgs, callableNodeType, userType, wrapDateTimeConvert);
556
+ }
557
+
558
+ if (!callableFuncType->IsConvertableTo (*callableNodeType, true )) {
559
+ if (!IsDateTimeConvertible (funcName, callableNodeType, callableFuncType, wrapDateTimeConvert)) {
560
+ TString diff = TStringBuilder () << " type mismatch, expected return type: " << PrintNode (callableNodeType, true ) <<
561
+ " , actual:" << PrintNode (callableFuncType, true );
562
+ UdfTerminate ((TStringBuilder () << pos << " UDF Function '" << funcName << " ' " << TruncateTypeDiff (diff)).c_str ());
563
+ }
564
+ MKQL_ENSURE (funcName == NUdf::TStringRef::Of (" DateTime2.Format" ) ||
565
+ funcName == NUdf::TStringRef::Of (" DateTime2.Convert" ),
566
+ " Unexpected function violates the convertible invariants" );
426
567
}
427
- MKQL_ENSURE (callableFuncType->IsConvertableTo (*callableNodeType, true ),
428
- " Function '" << funcName << " ' type mismatch, expected return type: " << PrintNode (callableNodeType, true ) <<
429
- " , actual:" << PrintNode (callableFuncType, true ));
430
568
MKQL_ENSURE (funcInfo.Implementation , " UDF implementation is not set for function " << funcName);
431
569
432
570
if (runConfigFuncType->IsVoid ()) {
433
571
if (ctx.ValidateMode == NUdf::EValidateMode::None && funcInfo.ModuleIR && funcInfo.IRFunctionName ) {
434
572
return new TUdfRunCodegeneratorNode (
435
- ctx.Mutables , std::move (funcName), std::move (typeConfig), pos, callableNodeType, callableFuncType, userType,
573
+ ctx.Mutables , std::move (funcName), std::move (typeConfig), pos, callableNodeType, callableFuncType, userType, wrapDateTimeConvert,
436
574
std::move (funcInfo.ModuleIRUniqID ), std::move (funcInfo.ModuleIR ), std::move (funcInfo.IRFunctionName ), std::move (funcInfo.Implementation )
437
575
);
438
576
}
439
- return CreateUdfWrapper<true >(ctx, std::move (funcName), std::move (typeConfig), pos, callableNodeType, callableFuncType, userType);
577
+ return CreateUdfWrapper<true >(ctx, std::move (funcName), std::move (typeConfig), pos, callableNodeType, callableFuncType, userType, wrapDateTimeConvert );
440
578
}
441
579
442
580
const auto runCfgCompNode = LocateNode (ctx.NodeLocator , *runCfgNode.GetNode ());
443
- return CreateUdfWrapper<false >(ctx, std::move (funcName), std::move (typeConfig), pos, runCfgCompNode, 1U , callableNodeType, userType);
581
+ return CreateUdfWrapper<false >(ctx, std::move (funcName), std::move (typeConfig), pos, runCfgCompNode, 1U , callableNodeType, userType, wrapDateTimeConvert );
444
582
}
445
583
446
584
IComputationNode* WrapScriptUdf (TCallable& callable, const TComputationNodeFactoryContext& ctx) {
@@ -479,7 +617,7 @@ IComputationNode* WrapScriptUdf(TCallable& callable, const TComputationNodeFacto
479
617
const auto funcTypeInfo = static_cast <TCallableType*>(callableResultType);
480
618
481
619
const auto programCompNode = LocateNode (ctx.NodeLocator , *programNode.GetNode ());
482
- return CreateUdfWrapper<false >(ctx, std::move (funcName), std::move (typeConfig), pos, programCompNode, 1U , funcTypeInfo, userType);
620
+ return CreateUdfWrapper<false >(ctx, std::move (funcName), std::move (typeConfig), pos, programCompNode, 1U , funcTypeInfo, userType, false );
483
621
}
484
622
485
623
}
0 commit comments