mkql_builtins_add.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  1. #include "mkql_builtins_impl.h" // Y_IGNORE
  2. #include "mkql_builtins_datetime.h"
  3. #include "mkql_builtins_decimal.h" // Y_IGNORE
  4. #include <yql/essentials/minikql/mkql_type_ops.h>
  5. namespace NKikimr {
  6. namespace NMiniKQL {
  7. namespace {
  8. template<typename TLeft, typename TRight, typename TOutput>
  9. struct TAdd : public TSimpleArithmeticBinary<TLeft, TRight, TOutput, TAdd<TLeft, TRight, TOutput>> {
  10. static constexpr auto NullMode = TKernel::ENullMode::Default;
  11. static TOutput Do(TOutput left, TOutput right)
  12. {
  13. return left + right;
  14. }
  15. #ifndef MKQL_DISABLE_CODEGEN
  16. static Value* Gen(Value* left, Value* right, const TCodegenContext&, BasicBlock*& block)
  17. {
  18. return std::is_integral<TOutput>() ? BinaryOperator::CreateAdd(left, right, "add", block) : BinaryOperator::CreateFAdd(left, right, "add", block);
  19. }
  20. #endif
  21. };
  22. template<typename TType>
  23. using TAggrAdd = TAdd<TType, TType, TType>;
  24. template<ui8 Precision>
  25. struct TDecimalAdd {
  26. static NUdf::TUnboxedValuePod Execute(const NUdf::TUnboxedValuePod& left, const NUdf::TUnboxedValuePod& right) {
  27. const auto l = left.GetInt128();
  28. const auto r = right.GetInt128();
  29. const auto a = l + r;
  30. using namespace NYql::NDecimal;
  31. if (IsNormal<Precision>(l) && IsNormal<Precision>(r) && IsNormal<Precision>(a))
  32. return NUdf::TUnboxedValuePod(a);
  33. if (IsNan(l) || IsNan(r) || !a)
  34. return NUdf::TUnboxedValuePod(Nan());
  35. else
  36. return NUdf::TUnboxedValuePod(a > 0 ? +Inf() : -Inf());
  37. }
  38. #ifndef MKQL_DISABLE_CODEGEN
  39. static Value* Generate(Value* left, Value* right, const TCodegenContext& ctx, BasicBlock*& block)
  40. {
  41. auto& context = ctx.Codegen.GetContext();
  42. const auto& bounds = NDecimal::GenBounds<Precision>(context);
  43. const auto l = GetterForInt128(left, block);
  44. const auto r = GetterForInt128(right, block);
  45. const auto add = BinaryOperator::CreateAdd(l, r, "add", block);
  46. const auto lok = NDecimal::GenInBounds(l, bounds.first, bounds.second, block);
  47. const auto rok = NDecimal::GenInBounds(r, bounds.first, bounds.second, block);
  48. const auto aok = NDecimal::GenInBounds(add, bounds.first, bounds.second, block);
  49. const auto bok = BinaryOperator::CreateAnd(lok, rok, "bok", block);
  50. const auto ok = BinaryOperator::CreateAnd(aok, bok, "ok", block);
  51. const auto bads = BasicBlock::Create(context, "bads", ctx.Func);
  52. const auto infs = BasicBlock::Create(context, "infs", ctx.Func);
  53. const auto done = BasicBlock::Create(context, "done", ctx.Func);
  54. const auto result = PHINode::Create(add->getType(), 3, "result", done);
  55. result->addIncoming(add, block);
  56. BranchInst::Create(done, bads, ok, block);
  57. block = bads;
  58. const auto lnan = NDecimal::GenIsNonComparable(l, context, block);
  59. const auto rnan = NDecimal::GenIsNonComparable(r, context, block);
  60. const auto anan = BinaryOperator::CreateOr(lnan, rnan, "anan", block);
  61. const auto null = ConstantInt::get(add->getType(), 0);
  62. const auto zero = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_EQ, add, null, "zero", block);
  63. const auto nan = BinaryOperator::CreateOr(anan, zero, "nan", block);
  64. result->addIncoming(GetDecimalNan(context), block);
  65. BranchInst::Create(done, infs, nan, block);
  66. block = infs;
  67. const auto plus = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_SGT, add, null, "plus", block);
  68. const auto inf = SelectInst::Create(plus, GetDecimalPlusInf(context), GetDecimalMinusInf(context), "inf", block);
  69. result->addIncoming(inf, block);
  70. BranchInst::Create(done, block);
  71. block = done;
  72. return SetterForInt128(result, block);
  73. }
  74. #endif
  75. static_assert(Precision <= NYql::NDecimal::MaxPrecision, "Too large precision!");
  76. };
  77. template<typename TLeft, typename TRight, typename TOutput, bool Tz = false>
  78. struct TDateTimeAddT {
  79. static_assert(std::is_integral<typename TLeft::TLayout>::value, "left must be integral");
  80. static_assert(std::is_integral<typename TRight::TLayout>::value, "right must be integral");
  81. static_assert(std::is_integral<typename TOutput::TLayout>::value, "output must be integral");
  82. static constexpr auto NullMode = TKernel::ENullMode::AlwaysNull;
  83. static NUdf::TUnboxedValuePod Execute(const NUdf::TUnboxedValuePod& left, const NUdf::TUnboxedValuePod& right)
  84. {
  85. const auto lv = ToScaledDate<TLeft>(left.template Get<typename TLeft::TLayout>());
  86. const auto rv = ToScaledDate<TRight>(right.template Get<typename TRight::TLayout>());
  87. const auto ret = lv + rv;
  88. if (IsBadScaledDate<TOutput>(ret)) {
  89. return NUdf::TUnboxedValuePod();
  90. }
  91. auto data = NUdf::TUnboxedValuePod(FromScaledDate<TOutput>(ret));
  92. if constexpr (Tz) {
  93. data.SetTimezoneId(((std::is_same<TLeft, NUdf::TDataType<NUdf::TInterval>>() || std::is_same<TLeft, NUdf::TDataType<NUdf::TInterval64>>()) ? right : left).GetTimezoneId());
  94. }
  95. return data;
  96. }
  97. #ifndef MKQL_DISABLE_CODEGEN
  98. static Value* Generate(Value* left, Value* right, const TCodegenContext& ctx, BasicBlock*& block)
  99. {
  100. auto& context = ctx.Codegen.GetContext();
  101. const auto lhs = GenToScaledDate<TLeft>(GetterFor<typename TLeft::TLayout>(left, context, block), context, block);
  102. const auto rhs = GenToScaledDate<TRight>(GetterFor<typename TRight::TLayout>(right, context, block), context, block);
  103. const auto add = BinaryOperator::CreateAdd(lhs, rhs, "add", block);
  104. const auto wide = SetterFor<typename TOutput::TLayout>(GenFromScaledDate<TOutput>(add, context, block), context, block);
  105. const auto bad = GenIsBadScaledDate<TOutput>(add, context, block);
  106. const auto type = Type::getInt128Ty(context);
  107. const auto zero = ConstantInt::get(type, 0);
  108. if constexpr (Tz) {
  109. const uint64_t init[] = {0ULL, 0xFFFFULL};
  110. const auto mask = ConstantInt::get(type, APInt(128, 2, init));
  111. const auto tzid = BinaryOperator::CreateAnd((std::is_same<TLeft, NUdf::TDataType<NUdf::TInterval>>() || std::is_same<TLeft, NUdf::TDataType<NUdf::TInterval64>>()) ? right : left, mask, "tzid", block);
  112. const auto full = BinaryOperator::CreateOr(wide, tzid, "full", block);
  113. const auto sel = SelectInst::Create(bad, zero, full, "sel", block);
  114. return sel;
  115. } else {
  116. const auto sel = SelectInst::Create(bad, zero, wide, "sel", block);
  117. return sel;
  118. }
  119. }
  120. #endif
  121. };
  122. template<typename TLeft, typename TRight, typename TOutput>
  123. struct TBigIntervalAdd {
  124. static_assert(std::is_same_v<typename TLeft::TLayout, i64>, "Left must be i64");
  125. static_assert(std::is_same_v<typename TRight::TLayout, i64>, "Right must be i64");
  126. static_assert(std::is_same_v<typename TOutput::TLayout, i64>, "Output must be i64");
  127. static constexpr auto NullMode = TKernel::ENullMode::AlwaysNull;
  128. static NUdf::TUnboxedValuePod Execute(const NUdf::TUnboxedValuePod& left, const NUdf::TUnboxedValuePod& right)
  129. {
  130. i64 lv = left.Get<i64>();
  131. i64 rv = right.Get<i64>();
  132. i64 ret = lv + rv;
  133. // detect overflow
  134. if (lv > 0 && rv > 0 && ret < 0) {
  135. return NUdf::TUnboxedValuePod();
  136. } else if (lv < 0 && rv < 0 && ret > 0) {
  137. return NUdf::TUnboxedValuePod();
  138. } else if (IsBadInterval<NUdf::TDataType<NUdf::TInterval64>>(ret)) {
  139. return NUdf::TUnboxedValuePod();
  140. }
  141. return NUdf::TUnboxedValuePod(ret);
  142. }
  143. #ifndef MKQL_DISABLE_CODEGEN
  144. static Value* Generate(Value* left, Value* right, const TCodegenContext& ctx, BasicBlock*& block)
  145. {
  146. auto& context = ctx.Codegen.GetContext();
  147. const auto lhs = GetterFor<i64>(left, context, block);
  148. const auto rhs = GetterFor<i64>(right, context, block);
  149. const auto add = BinaryOperator::CreateAdd(lhs, rhs, "add", block);
  150. const auto wide = SetterFor<i64>(add, context, block);
  151. const auto lneg = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_SLT, lhs, ConstantInt::get(lhs->getType(), 0), "lneg", block);
  152. const auto rneg = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_SLT, rhs, ConstantInt::get(rhs->getType(), 0), "rneg", block);
  153. const auto apos = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_SGT, add, ConstantInt::get(add->getType(), 0), "apos", block);
  154. const auto posAddNegArg = BinaryOperator::CreateAnd(apos, BinaryOperator::CreateAnd(lneg, rneg, "negArg", block), "posAddNegArg", block);
  155. const auto lpos = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_SGT, lhs, ConstantInt::get(lhs->getType(), 0), "lpos", block);
  156. const auto rpos = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_SGT, rhs, ConstantInt::get(rhs->getType(), 0), "rpos", block);
  157. const auto aneg = CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_SLT, add, ConstantInt::get(add->getType(), 0), "aneg", block);
  158. const auto negAddPosArg = BinaryOperator::CreateAnd(aneg, BinaryOperator::CreateAnd(lpos, rpos, "posArg", block), "negAddPosArg", block);
  159. const auto bad = BinaryOperator::CreateOr(
  160. BinaryOperator::CreateOr(posAddNegArg, negAddPosArg, "overflow", block),
  161. GenIsBadInterval<NUdf::TDataType<NUdf::TInterval64>>(add, context, block),
  162. "bad", block);
  163. const auto zero = ConstantInt::get(Type::getInt128Ty(context), 0);
  164. const auto sel = SelectInst::Create(bad, zero, wide, "sel", block);
  165. return sel;
  166. }
  167. #endif
  168. };
  169. template<typename TLeft, typename TRight, typename TOutput>
  170. using TDateTimeAdd = TDateTimeAddT<TLeft, TRight, TOutput, false>;
  171. template<typename TLeft, typename TRight, typename TOutput>
  172. using TDateTimeAddTz = TDateTimeAddT<TLeft, TRight, TOutput, true>;
  173. template <bool Tz, typename TIntervalType, template<typename, typename, typename> class TAdder>
  174. void RegisterAddDateAndInterval(IBuiltinFunctionRegistry& registry) {
  175. using TDate1 = std::conditional_t<Tz, NUdf::TDataType<NUdf::TTzDate>, NUdf::TDataType<NUdf::TDate>>;
  176. using TDate2 = std::conditional_t<Tz, NUdf::TDataType<NUdf::TTzDatetime>, NUdf::TDataType<NUdf::TDatetime>>;
  177. using TDate3 = std::conditional_t<Tz, NUdf::TDataType<NUdf::TTzTimestamp>, NUdf::TDataType<NUdf::TTimestamp>>;
  178. using TDate1Big = std::conditional_t<Tz, NUdf::TDataType<NUdf::TTzDate32>, NUdf::TDataType<NUdf::TDate32>>;
  179. using TDate2Big = std::conditional_t<Tz, NUdf::TDataType<NUdf::TTzDatetime64>, NUdf::TDataType<NUdf::TDatetime64>>;
  180. using TDate3Big = std::conditional_t<Tz, NUdf::TDataType<NUdf::TTzTimestamp64>, NUdf::TDataType<NUdf::TTimestamp64>>;
  181. RegisterFunctionBinPolyOpt<TDate1, TIntervalType,
  182. TDate1, TAdder, TBinaryArgsOptWithNullableResult>(registry, "Add");
  183. RegisterFunctionBinPolyOpt<TDate2, TIntervalType,
  184. TDate2, TAdder, TBinaryArgsOptWithNullableResult>(registry, "Add");
  185. RegisterFunctionBinPolyOpt<TDate3, TIntervalType,
  186. TDate3, TAdder, TBinaryArgsOptWithNullableResult>(registry, "Add");
  187. RegisterFunctionBinPolyOpt<TIntervalType, TDate1,
  188. TDate1, TAdder, TBinaryArgsOptWithNullableResult>(registry, "Add");
  189. RegisterFunctionBinPolyOpt<TIntervalType, TDate2,
  190. TDate2, TAdder, TBinaryArgsOptWithNullableResult>(registry, "Add");
  191. RegisterFunctionBinPolyOpt<TIntervalType, TDate3,
  192. TDate3, TAdder, TBinaryArgsOptWithNullableResult>(registry, "Add");
  193. RegisterFunctionBinPolyOpt<TDate1Big, TIntervalType,
  194. TDate1Big, TAdder, TBinaryArgsOptWithNullableResult>(registry, "Add");
  195. RegisterFunctionBinPolyOpt<TDate2Big, TIntervalType,
  196. TDate2Big, TAdder, TBinaryArgsOptWithNullableResult>(registry, "Add");
  197. RegisterFunctionBinPolyOpt<TDate3Big, TIntervalType,
  198. TDate3Big, TAdder, TBinaryArgsOptWithNullableResult>(registry, "Add");
  199. RegisterFunctionBinPolyOpt<TIntervalType, TDate1Big,
  200. TDate1Big, TAdder, TBinaryArgsOptWithNullableResult>(registry, "Add");
  201. RegisterFunctionBinPolyOpt<TIntervalType, TDate2Big,
  202. TDate2Big, TAdder, TBinaryArgsOptWithNullableResult>(registry, "Add");
  203. RegisterFunctionBinPolyOpt<TIntervalType, TDate3Big,
  204. TDate3Big, TAdder, TBinaryArgsOptWithNullableResult>(registry, "Add");
  205. }
  206. template<typename TType>
  207. using TIntervalAggrAdd = TDateTimeAdd<TType, TType, TType>;
  208. }
  209. void RegisterAdd(IBuiltinFunctionRegistry& registry) {
  210. RegisterBinaryNumericFunctionOpt<TAdd, TBinaryArgsOpt>(registry, "Add");
  211. NDecimal::RegisterBinaryFunctionForAllPrecisions<TDecimalAdd, TBinaryArgsOpt>(registry, "Add_");
  212. RegisterAddDateAndInterval<false, NUdf::TDataType<NUdf::TInterval>, TDateTimeAdd>(registry);
  213. RegisterAddDateAndInterval<true, NUdf::TDataType<NUdf::TInterval>, TDateTimeAddTz>(registry);
  214. RegisterAddDateAndInterval<false, NUdf::TDataType<NUdf::TInterval64>, TDateTimeAdd>(registry);
  215. RegisterAddDateAndInterval<true, NUdf::TDataType<NUdf::TInterval64>, TDateTimeAddTz>(registry);
  216. RegisterFunctionBinPolyOpt<NUdf::TDataType<NUdf::TInterval>, NUdf::TDataType<NUdf::TInterval>,
  217. NUdf::TDataType<NUdf::TInterval>, TDateTimeAdd, TBinaryArgsOptWithNullableResult>(registry, "Add");
  218. RegisterFunctionBinPolyOpt<NUdf::TDataType<NUdf::TInterval64>, NUdf::TDataType<NUdf::TInterval64>,
  219. NUdf::TDataType<NUdf::TInterval64>, TBigIntervalAdd, TBinaryArgsOptWithNullableResult>(registry, "Add");
  220. RegisterFunctionBinPolyOpt<NUdf::TDataType<NUdf::TInterval64>, NUdf::TDataType<NUdf::TInterval>,
  221. NUdf::TDataType<NUdf::TInterval64>, TBigIntervalAdd, TBinaryArgsOptWithNullableResult>(registry, "Add");
  222. RegisterFunctionBinPolyOpt<NUdf::TDataType<NUdf::TInterval>, NUdf::TDataType<NUdf::TInterval64>,
  223. NUdf::TDataType<NUdf::TInterval64>, TBigIntervalAdd, TBinaryArgsOptWithNullableResult>(registry, "Add");
  224. }
  225. template <bool Tz, bool BigDate, bool BigInterval>
  226. void RegisterDateAddInterval(TKernelFamilyBase& owner) {
  227. using TDateLeft1 = std::conditional_t<BigDate,
  228. std::conditional_t<Tz, NUdf::TDataType<NUdf::TTzDate32>, NUdf::TDataType<NUdf::TDate32>>,
  229. std::conditional_t<Tz, NUdf::TDataType<NUdf::TTzDate>, NUdf::TDataType<NUdf::TDate>>>;
  230. using TDateLeft2 = std::conditional_t<BigDate,
  231. std::conditional_t<Tz, NUdf::TDataType<NUdf::TTzDatetime64>, NUdf::TDataType<NUdf::TDatetime64>>,
  232. std::conditional_t<Tz, NUdf::TDataType<NUdf::TTzDatetime>, NUdf::TDataType<NUdf::TDatetime>>>;
  233. using TDateLeft3 = std::conditional_t<BigDate,
  234. std::conditional_t<Tz, NUdf::TDataType<NUdf::TTzTimestamp64>, NUdf::TDataType<NUdf::TTimestamp64>>,
  235. std::conditional_t<Tz, NUdf::TDataType<NUdf::TTzTimestamp>, NUdf::TDataType<NUdf::TTimestamp>>>;
  236. using TIntervalRight = std::conditional_t<BigInterval,
  237. NUdf::TDataType<NUdf::TInterval64>, NUdf::TDataType<NUdf::TInterval>>;
  238. if constexpr (Tz) {
  239. AddBinaryKernelPoly<TDateLeft1, TIntervalRight, TDateLeft1, TDateTimeAddTz>(owner);
  240. AddBinaryKernelPoly<TDateLeft2, TIntervalRight, TDateLeft2, TDateTimeAddTz>(owner);
  241. AddBinaryKernelPoly<TDateLeft3, TIntervalRight, TDateLeft3, TDateTimeAddTz>(owner);
  242. } else {
  243. AddBinaryKernelPoly<TDateLeft1, TIntervalRight, TDateLeft1, TDateTimeAdd>(owner);
  244. AddBinaryKernelPoly<TDateLeft2, TIntervalRight, TDateLeft2, TDateTimeAdd>(owner);
  245. AddBinaryKernelPoly<TDateLeft3, TIntervalRight, TDateLeft3, TDateTimeAdd>(owner);
  246. }
  247. }
  248. template <bool Tz, bool BigDate, bool BigInterval>
  249. void RegisterIntervalAddDate(TKernelFamilyBase& owner) {
  250. using TIntervalLeft = std::conditional_t<BigInterval,
  251. NUdf::TDataType<NUdf::TInterval64>, NUdf::TDataType<NUdf::TInterval>>;
  252. using TDateRight1 = std::conditional_t<BigDate,
  253. std::conditional_t<Tz, NUdf::TDataType<NUdf::TTzDate32>, NUdf::TDataType<NUdf::TDate32>>,
  254. std::conditional_t<Tz, NUdf::TDataType<NUdf::TTzDate>, NUdf::TDataType<NUdf::TDate>>>;
  255. using TDateRight2 = std::conditional_t<BigDate,
  256. std::conditional_t<Tz, NUdf::TDataType<NUdf::TTzDatetime64>, NUdf::TDataType<NUdf::TDatetime64>>,
  257. std::conditional_t<Tz, NUdf::TDataType<NUdf::TTzDatetime>, NUdf::TDataType<NUdf::TDatetime>>>;
  258. using TDateRight3 = std::conditional_t<BigDate,
  259. std::conditional_t<Tz, NUdf::TDataType<NUdf::TTzTimestamp64>, NUdf::TDataType<NUdf::TTimestamp64>>,
  260. std::conditional_t<Tz, NUdf::TDataType<NUdf::TTzTimestamp>, NUdf::TDataType<NUdf::TTimestamp>>>;
  261. if constexpr (Tz) {
  262. AddBinaryKernelPoly<TIntervalLeft, TDateRight1, TDateRight1, TDateTimeAddTz>(owner);
  263. AddBinaryKernelPoly<TIntervalLeft, TDateRight2, TDateRight2, TDateTimeAddTz>(owner);
  264. AddBinaryKernelPoly<TIntervalLeft, TDateRight3, TDateRight3, TDateTimeAddTz>(owner);
  265. } else {
  266. AddBinaryKernelPoly<TIntervalLeft, TDateRight1, TDateRight1, TDateTimeAdd>(owner);
  267. AddBinaryKernelPoly<TIntervalLeft, TDateRight2, TDateRight2, TDateTimeAdd>(owner);
  268. AddBinaryKernelPoly<TIntervalLeft, TDateRight3, TDateRight3, TDateTimeAdd>(owner);
  269. }
  270. }
  271. template <bool BigInterval1, bool BigInterval2>
  272. void RegisterIntervalAddInterval(TKernelFamilyBase& owner) {
  273. using TLeft = std::conditional_t<BigInterval1,
  274. NUdf::TDataType<NUdf::TInterval64>, NUdf::TDataType<NUdf::TInterval>>;
  275. using TRight = std::conditional_t<BigInterval2,
  276. NUdf::TDataType<NUdf::TInterval64>, NUdf::TDataType<NUdf::TInterval>>;
  277. using TOutput = std::conditional_t<BigInterval1 || BigInterval2,
  278. NUdf::TDataType<NUdf::TInterval64>, NUdf::TDataType<NUdf::TInterval>>;
  279. if constexpr (BigInterval1 || BigInterval2) {
  280. AddBinaryKernelPoly<TLeft, TRight, TOutput, TBigIntervalAdd>(owner);
  281. } else {
  282. AddBinaryKernelPoly<TLeft, TRight, TOutput, TDateTimeAdd>(owner);
  283. }
  284. }
  285. void RegisterAdd(TKernelFamilyMap& kernelFamilyMap) {
  286. auto family = std::make_unique<TKernelFamilyBase>();
  287. AddBinaryIntegralKernels<TAdd>(*family);
  288. AddBinaryRealKernels<TAdd>(*family);
  289. AddBinaryDecimalKernels<TDecimalAdd>(*family);
  290. RegisterDateAddInterval<false, false, false>(*family);
  291. RegisterDateAddInterval<true, false, false>(*family);
  292. RegisterDateAddInterval<false, true, false>(*family);
  293. RegisterDateAddInterval<true, true, false>(*family);
  294. RegisterDateAddInterval<false, false, true>(*family);
  295. RegisterDateAddInterval<true, false, true>(*family);
  296. RegisterDateAddInterval<false, true, true>(*family);
  297. RegisterDateAddInterval<true, true, true>(*family);
  298. RegisterIntervalAddDate<false, false, false>(*family);
  299. RegisterIntervalAddDate<true, false, false>(*family);
  300. RegisterIntervalAddDate<false, true, false>(*family);
  301. RegisterIntervalAddDate<true, true, false>(*family);
  302. RegisterIntervalAddDate<false, false, true>(*family);
  303. RegisterIntervalAddDate<true, false, true>(*family);
  304. RegisterIntervalAddDate<false, true, true>(*family);
  305. RegisterIntervalAddDate<true, true, true>(*family);
  306. RegisterIntervalAddInterval<false, false>(*family);
  307. RegisterIntervalAddInterval<false, true>(*family);
  308. RegisterIntervalAddInterval<true, false>(*family);
  309. RegisterIntervalAddInterval<true, true>(*family);
  310. kernelFamilyMap["Add"] = std::move(family);
  311. }
  312. void RegisterAggrAdd(IBuiltinFunctionRegistry& registry) {
  313. RegisterNumericAggregateFunction<TAggrAdd, TBinaryArgsSameOpt>(registry, "AggrAdd");
  314. RegisterAggregateFunctionPoly<NUdf::TDataType<NUdf::TInterval>, TIntervalAggrAdd, TBinaryArgsSameOptArgsWithNullableResult>(registry, "AggrAdd");
  315. NDecimal::RegisterAggregateFunctionForAllPrecisions<TDecimalAdd, TBinaryArgsSameOpt>(registry, "AggrAdd_");
  316. }
  317. } // namespace NMiniKQL
  318. } // namespace NKikimr