11#pragma once
22#include < type_traits>
33#include < Core/AccurateComparison.h>
4+ #include < Core/DecimalFunctions.h>
45#include < Common/DateLUTImpl.h>
56
67#include < DataTypes/DataTypeDate.h>
1415#include < Functions/FunctionHelpers.h>
1516#include < Functions/castTypeToEither.h>
1617#include < Functions/extractTimeZoneFromFunctionArguments.h>
17- #include < Functions/TransformDateTime64.h>
1818
1919#include < IO/WriteHelpers.h>
2020
@@ -36,7 +36,9 @@ namespace ErrorCodes
3636// / Corresponding types:
3737// / - UInt16 => DataTypeDate
3838// / - UInt32 => DataTypeDateTime
39+ // / - Int32 => DataTypeDate32
3940// / - DateTime64 => DataTypeDateTime64
41+ // / - Int8 => error
4042// / Please note that INPUT and OUTPUT types may differ, e.g.:
4143// / - 'AddSecondsImpl::execute(UInt32, ...) -> UInt32' is available to the ClickHouse users as 'addSeconds(DateTime, ...) -> DateTime'
4244// / - 'AddSecondsImpl::execute(UInt16, ...) -> UInt32' is available to the ClickHouse users as 'addSeconds(Date, ...) -> DateTime'
@@ -45,140 +47,98 @@ struct AddNanosecondsImpl
4547{
4648 static constexpr auto name = " addNanoseconds" ;
4749
48- static inline NO_SANITIZE_UNDEFINED DecimalUtils::DecimalComponents<DateTime64>
49- execute (DecimalUtils::DecimalComponents<DateTime64> t, Int64 delta, const DateLUTImpl &, UInt16 scale = DataTypeDateTime64::default_scale)
50- {
51- Int64 multiplier = DecimalUtils::scaleMultiplier<DateTime64>(9 - scale);
52- auto division = std::div (t.fractional * multiplier + delta, static_cast <Int64>(1000000000 ));
53- return {t.whole * multiplier + division.quot , t.fractional * multiplier + delta};
54- }
55-
5650 static inline NO_SANITIZE_UNDEFINED DateTime64
5751 execute (DateTime64 t, Int64 delta, const DateLUTImpl &, UInt16 scale = 0 )
5852 {
5953 Int64 multiplier = DecimalUtils::scaleMultiplier<DateTime64>(9 - scale);
60- return t * multiplier + delta;
54+ return DateTime64 ( DecimalUtils::multiplyAdd (t. value , multiplier, delta)) ;
6155 }
6256
63- static inline NO_SANITIZE_UNDEFINED UInt32 execute (UInt32 t, Int64 delta, const DateLUTImpl &, UInt16 = 0 )
57+ static inline NO_SANITIZE_UNDEFINED DateTime64 execute (UInt32 t, Int64 delta, const DateLUTImpl &, UInt16 = 0 )
6458 {
6559 Int64 multiplier = DecimalUtils::scaleMultiplier<DateTime64>(9 );
66- return static_cast <UInt32 >(t * multiplier + delta);
60+ return DateTime64 ( DecimalUtils::multiplyAdd ( static_cast <Int64 >(t), multiplier, delta) );
6761 }
6862
69- static inline NO_SANITIZE_UNDEFINED DateTime64 execute (UInt16, Int64, const DateLUTImpl &, UInt16 = 0 )
63+ static inline NO_SANITIZE_UNDEFINED Int8 execute (UInt16, Int64, const DateLUTImpl &, UInt16 = 0 )
7064 {
71- throw Exception (ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT , " addNanoSeconds () cannot be used with Date" );
65+ throw Exception (ErrorCodes::LOGICAL_ERROR , " addNanoseconds () cannot be used with Date" );
7266 }
7367
74- static inline NO_SANITIZE_UNDEFINED DateTime64 execute (Int32, Int64, const DateLUTImpl &, UInt16 = 0 )
68+ static inline NO_SANITIZE_UNDEFINED Int8 execute (Int32, Int64, const DateLUTImpl &, UInt16 = 0 )
7569 {
76- throw Exception (ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT , " addNanoSeconds () cannot be used with Date32" );
70+ throw Exception (ErrorCodes::LOGICAL_ERROR , " addNanoseconds () cannot be used with Date32" );
7771 }
7872};
7973
8074struct AddMicrosecondsImpl
8175{
8276 static constexpr auto name = " addMicroseconds" ;
8377
84- static inline NO_SANITIZE_UNDEFINED DecimalUtils::DecimalComponents<DateTime64>
85- execute (DecimalUtils::DecimalComponents<DateTime64> t, Int64 delta, const DateLUTImpl &, UInt16 scale = 0 )
86- {
87- Int64 multiplier = DecimalUtils::scaleMultiplier<DateTime64>(std::abs (6 - scale));
88- if (scale <= 6 )
89- {
90- auto division = std::div ((t.fractional + delta), static_cast <Int64>(10e6 ));
91- return {t.whole * multiplier + division.quot , division.rem };
92- }
93- else
94- {
95- auto division = std::div ((t.fractional + delta * multiplier), static_cast <Int64>(10e6 * multiplier));
96- return {t.whole + division.quot , division.rem };
97- }
98- }
99-
10078 static inline NO_SANITIZE_UNDEFINED DateTime64
10179 execute (DateTime64 t, Int64 delta, const DateLUTImpl &, UInt16 scale = 0 )
10280 {
10381 Int64 multiplier = DecimalUtils::scaleMultiplier<DateTime64>(std::abs (6 - scale));
104- return scale <= 6 ? t * multiplier + delta : t + delta * multiplier;
82+ return DateTime64 (scale <= 6
83+ ? DecimalUtils::multiplyAdd (t.value , multiplier, delta)
84+ : DecimalUtils::multiplyAdd (delta, multiplier, t.value ));
10585 }
10686
107- static inline NO_SANITIZE_UNDEFINED UInt32 execute (UInt32 t, Int64 delta, const DateLUTImpl &, UInt16 = 0 )
87+ static inline NO_SANITIZE_UNDEFINED DateTime64 execute (UInt32 t, Int64 delta, const DateLUTImpl &, UInt16 = 0 )
10888 {
10989 Int64 multiplier = DecimalUtils::scaleMultiplier<DateTime64>(6 );
110- return static_cast <UInt32 >(t * multiplier + delta);
90+ return DateTime64 ( DecimalUtils::multiplyAdd ( static_cast <Int64 >(t), multiplier, delta) );
11191 }
11292
113- static inline NO_SANITIZE_UNDEFINED DateTime64 execute (UInt16, Int64, const DateLUTImpl &, UInt16 = 0 )
93+ static inline NO_SANITIZE_UNDEFINED Int8 execute (UInt16, Int64, const DateLUTImpl &, UInt16 = 0 )
11494 {
115- throw Exception (ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT , " addMicroSeconds () cannot be used with Date" );
95+ throw Exception (ErrorCodes::LOGICAL_ERROR , " addMicroseconds () cannot be used with Date" );
11696 }
11797
118- static inline NO_SANITIZE_UNDEFINED DateTime64 execute (Int32, Int64, const DateLUTImpl &, UInt16 = 0 )
98+ static inline NO_SANITIZE_UNDEFINED Int8 execute (Int32, Int64, const DateLUTImpl &, UInt16 = 0 )
11999 {
120- throw Exception (ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT , " addMicroSeconds () cannot be used with Date32" );
100+ throw Exception (ErrorCodes::LOGICAL_ERROR , " addMicroseconds () cannot be used with Date32" );
121101 }
122102};
123103
124104struct AddMillisecondsImpl
125105{
126106 static constexpr auto name = " addMilliseconds" ;
127107
128- static inline NO_SANITIZE_UNDEFINED DecimalUtils::DecimalComponents<DateTime64>
129- execute (DecimalUtils::DecimalComponents<DateTime64> t, Int64 delta, const DateLUTImpl &, UInt16 scale = DataTypeDateTime64::default_scale)
130- {
131- Int64 multiplier = DecimalUtils::scaleMultiplier<DateTime64>(std::abs (3 - scale));
132- if (scale <= 3 )
133- {
134- auto division = std::div ((t.fractional + delta), static_cast <Int64>(1000 ));
135- return {t.whole * multiplier + division.quot , division.rem };
136- }
137- else
138- {
139- auto division = std::div ((t.fractional + delta * multiplier), static_cast <Int64>(1000 * multiplier));
140- return {t.whole + division.quot ,division.rem };
141- }
142- }
143-
144108 static inline NO_SANITIZE_UNDEFINED DateTime64
145109 execute (DateTime64 t, Int64 delta, const DateLUTImpl &, UInt16 scale = 0 )
146110 {
147111 Int64 multiplier = DecimalUtils::scaleMultiplier<DateTime64>(std::abs (3 - scale));
148- return scale <= 3 ? t * multiplier + delta : t + delta * multiplier;
112+ return DateTime64 (scale <= 3
113+ ? DecimalUtils::multiplyAdd (t.value , multiplier, delta)
114+ : DecimalUtils::multiplyAdd (delta, multiplier, t.value ));
149115 }
150116
151- static inline NO_SANITIZE_UNDEFINED UInt32 execute (UInt32 t, Int64 delta, const DateLUTImpl &, UInt16 = 0 )
117+ static inline NO_SANITIZE_UNDEFINED DateTime64 execute (UInt32 t, Int64 delta, const DateLUTImpl &, UInt16 = 0 )
152118 {
153119 Int64 multiplier = DecimalUtils::scaleMultiplier<DateTime64>(3 );
154- return static_cast <UInt32 >(t * multiplier + delta);
120+ return DateTime64 ( DecimalUtils::multiplyAdd ( static_cast <Int64 >(t), multiplier, delta) );
155121 }
156122
157- static inline NO_SANITIZE_UNDEFINED DateTime64 execute (UInt16, Int64, const DateLUTImpl &, UInt16 = 0 )
123+ static inline NO_SANITIZE_UNDEFINED Int8 execute (UInt16, Int64, const DateLUTImpl &, UInt16 = 0 )
158124 {
159- throw Exception (ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT , " addMilliSeconds () cannot be used with Date" );
125+ throw Exception (ErrorCodes::LOGICAL_ERROR , " addMilliseconds () cannot be used with Date" );
160126 }
161127
162- static inline NO_SANITIZE_UNDEFINED DateTime64 execute (Int32, Int64, const DateLUTImpl &, UInt16 = 0 )
128+ static inline NO_SANITIZE_UNDEFINED Int8 execute (Int32, Int64, const DateLUTImpl &, UInt16 = 0 )
163129 {
164- throw Exception (ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT , " addMilliSeconds () cannot be used with Date32" );
130+ throw Exception (ErrorCodes::LOGICAL_ERROR , " addMilliseconds () cannot be used with Date32" );
165131 }
166132};
167133
168134struct AddSecondsImpl
169135{
170136 static constexpr auto name = " addSeconds" ;
171137
172- static inline NO_SANITIZE_UNDEFINED DecimalUtils::DecimalComponents<DateTime64>
173- execute (DecimalUtils::DecimalComponents<DateTime64> t, Int64 delta, const DateLUTImpl &, UInt16 = 0 )
174- {
175- return {t.whole + delta, t.fractional };
176- }
177-
178138 static inline NO_SANITIZE_UNDEFINED DateTime64
179139 execute (DateTime64 t, Int64 delta, const DateLUTImpl &, UInt16 scale = 0 )
180140 {
181- return t + delta * DecimalUtils::scaleMultiplier<DateTime64>(scale);
141+ return DateTime64 ( DecimalUtils::multiplyAdd ( delta, DecimalUtils::scaleMultiplier<DateTime64>(scale), t. value ) );
182142 }
183143
184144 static inline NO_SANITIZE_UNDEFINED UInt32 execute (UInt32 t, Int64 delta, const DateLUTImpl &, UInt16 = 0 )
@@ -189,6 +149,7 @@ struct AddSecondsImpl
189149 static inline NO_SANITIZE_UNDEFINED Int64 execute (Int32 d, Int64 delta, const DateLUTImpl & time_zone, UInt16 = 0 )
190150 {
191151 // use default datetime64 scale
152+ static_assert (DataTypeDateTime64::default_scale == 3 , " " );
192153 return (time_zone.fromDayNum (ExtendedDayNum (d)) + delta) * 1000 ;
193154 }
194155
@@ -202,12 +163,6 @@ struct AddMinutesImpl
202163{
203164 static constexpr auto name = " addMinutes" ;
204165
205- static inline NO_SANITIZE_UNDEFINED DecimalUtils::DecimalComponents<DateTime64>
206- execute (DecimalUtils::DecimalComponents<DateTime64> t, Int64 delta, const DateLUTImpl &, UInt16 = 0 )
207- {
208- return {t.whole + delta * 60 , t.fractional };
209- }
210-
211166 static inline NO_SANITIZE_UNDEFINED DateTime64
212167 execute (DateTime64 t, Int64 delta, const DateLUTImpl &, UInt16 scale = 0 )
213168 {
@@ -222,6 +177,7 @@ struct AddMinutesImpl
222177 static inline NO_SANITIZE_UNDEFINED Int64 execute (Int32 d, Int64 delta, const DateLUTImpl & time_zone, UInt16 = 0 )
223178 {
224179 // use default datetime64 scale
180+ static_assert (DataTypeDateTime64::default_scale == 3 , " " );
225181 return (time_zone.fromDayNum (ExtendedDayNum (d)) + delta * 60 ) * 1000 ;
226182 }
227183
@@ -235,12 +191,6 @@ struct AddHoursImpl
235191{
236192 static constexpr auto name = " addHours" ;
237193
238- static inline NO_SANITIZE_UNDEFINED DecimalUtils::DecimalComponents<DateTime64>
239- execute (DecimalUtils::DecimalComponents<DateTime64> t, Int64 delta, const DateLUTImpl &, UInt16 = 0 )
240- {
241- return {t.whole + delta * 3600 , t.fractional };
242- }
243-
244194 static inline NO_SANITIZE_UNDEFINED DateTime64
245195 execute (DateTime64 t, Int64 delta, const DateLUTImpl &, UInt16 scale = 0 )
246196 {
@@ -255,6 +205,7 @@ struct AddHoursImpl
255205 static inline NO_SANITIZE_UNDEFINED Int64 execute (Int32 d, Int64 delta, const DateLUTImpl & time_zone, UInt16 = 0 )
256206 {
257207 // use default datetime64 scale
208+ static_assert (DataTypeDateTime64::default_scale == 3 , " " );
258209 return (time_zone.fromDayNum (ExtendedDayNum (d)) + delta * 3600 ) * 1000 ;
259210 }
260211
@@ -268,12 +219,6 @@ struct AddDaysImpl
268219{
269220 static constexpr auto name = " addDays" ;
270221
271- static inline NO_SANITIZE_UNDEFINED DecimalUtils::DecimalComponents<DateTime64>
272- execute (DecimalUtils::DecimalComponents<DateTime64> t, Int64 delta, const DateLUTImpl & time_zone, UInt16 = 0 )
273- {
274- return {time_zone.addDays (t.whole , delta), t.fractional };
275- }
276-
277222 static inline NO_SANITIZE_UNDEFINED DateTime64
278223 execute (DateTime64 t, Int64 delta, const DateLUTImpl & time_zone, UInt16 scale = 0 )
279224 {
@@ -302,12 +247,6 @@ struct AddWeeksImpl
302247{
303248 static constexpr auto name = " addWeeks" ;
304249
305- static inline NO_SANITIZE_UNDEFINED DecimalUtils::DecimalComponents<DateTime64>
306- execute (DecimalUtils::DecimalComponents<DateTime64> t, Int64 delta, const DateLUTImpl & time_zone, UInt16 = 0 )
307- {
308- return {time_zone.addWeeks (t.whole , delta), t.fractional };
309- }
310-
311250 static inline NO_SANITIZE_UNDEFINED DateTime64
312251 execute (DateTime64 t, Int64 delta, const DateLUTImpl & time_zone, UInt16 scale = 0 )
313252 {
@@ -336,12 +275,6 @@ struct AddMonthsImpl
336275{
337276 static constexpr auto name = " addMonths" ;
338277
339- static inline NO_SANITIZE_UNDEFINED DecimalUtils::DecimalComponents<DateTime64>
340- execute (DecimalUtils::DecimalComponents<DateTime64> t, Int64 delta, const DateLUTImpl & time_zone, UInt16 = 0 )
341- {
342- return {time_zone.addMonths (t.whole , delta), t.fractional };
343- }
344-
345278 static inline NO_SANITIZE_UNDEFINED DateTime64
346279 execute (DateTime64 t, Int64 delta, const DateLUTImpl & time_zone, UInt16 scale = 0 )
347280 {
@@ -370,12 +303,6 @@ struct AddQuartersImpl
370303{
371304 static constexpr auto name = " addQuarters" ;
372305
373- static inline DecimalUtils::DecimalComponents<DateTime64>
374- execute (DecimalUtils::DecimalComponents<DateTime64> t, Int64 delta, const DateLUTImpl & time_zone, UInt16 = 0 )
375- {
376- return {time_zone.addQuarters (t.whole , delta), t.fractional };
377- }
378-
379306 static inline NO_SANITIZE_UNDEFINED DateTime64
380307 execute (DateTime64 t, Int64 delta, const DateLUTImpl & time_zone, UInt16 scale = 0 )
381308 {
@@ -404,12 +331,6 @@ struct AddYearsImpl
404331{
405332 static constexpr auto name = " addYears" ;
406333
407- static inline NO_SANITIZE_UNDEFINED DecimalUtils::DecimalComponents<DateTime64>
408- execute (DecimalUtils::DecimalComponents<DateTime64> t, Int64 delta, const DateLUTImpl & time_zone, UInt16 = 0 )
409- {
410- return {time_zone.addYears (t.whole , delta), t.fractional };
411- }
412-
413334 static inline NO_SANITIZE_UNDEFINED DateTime64
414335 execute (DateTime64 t, Int64 delta, const DateLUTImpl & time_zone, UInt16 scale = 0 )
415336 {
@@ -581,11 +502,11 @@ namespace date_and_time_type_details
581502// Compile-time mapping of value (DataType::FieldType) types to corresponding DataType
582503template <typename FieldType> struct ResultDataTypeMap {};
583504template <> struct ResultDataTypeMap <UInt16> { using ResultDataType = DataTypeDate; };
584- template <> struct ResultDataTypeMap <Int16> { using ResultDataType = DataTypeDate; };
585505template <> struct ResultDataTypeMap <UInt32> { using ResultDataType = DataTypeDateTime; };
586506template <> struct ResultDataTypeMap <Int32> { using ResultDataType = DataTypeDate32; };
587507template <> struct ResultDataTypeMap <DateTime64> { using ResultDataType = DataTypeDateTime64; };
588508template <> struct ResultDataTypeMap <Int64> { using ResultDataType = DataTypeDateTime64; };
509+ template <> struct ResultDataTypeMap <Int8> { using ResultDataType = DataTypeInt8; }; // error
589510}
590511
591512template <typename Transform>
@@ -705,6 +626,10 @@ class FunctionDateOrDateTimeAddInterval : public IFunction
705626
706627 return std::make_shared<DataTypeDateTime64>(target_scale.value_or (DataTypeDateTime64::default_scale), std::move (timezone));
707628 }
629+ else if constexpr (std::is_same_v<ResultDataType, DataTypeInt8>)
630+ {
631+ throw Exception (ErrorCodes::ILLEGAL_TYPE_OF_ARGUMENT, " {} cannot be used with {}" , getName (), arguments[0 ].type ->getName ());
632+ }
708633
709634 throw Exception (ErrorCodes::LOGICAL_ERROR, " Unexpected result type in datetime add interval function" );
710635 }
0 commit comments