66#include " duckdb/common/serializer/serializer.hpp"
77#include " duckdb/common/serializer/deserializer.hpp"
88
9- #include < algorithm>
10- #include < cmath>
119#include < stdlib.h>
1210
1311namespace duckdb {
@@ -17,6 +15,50 @@ struct ApproxQuantileState {
1715 idx_t pos;
1816};
1917
18+ struct ApproxQuantileCoding {
19+ template <typename INPUT_TYPE, typename SAVE_TYPE>
20+ static SAVE_TYPE Encode (const INPUT_TYPE &input) {
21+ return Cast::template Operation<INPUT_TYPE, SAVE_TYPE>(input);
22+ }
23+
24+ template <typename SAVE_TYPE, typename TARGET_TYPE>
25+ static bool Decode (const SAVE_TYPE &source, TARGET_TYPE &target) {
26+ // The result is approximate, so clamp instead of overflowing.
27+ if (TryCast::Operation (source, target, false )) {
28+ return true ;
29+ } else if (source < 0 ) {
30+ target = NumericLimits<TARGET_TYPE>::Minimum ();
31+ } else {
32+ target = NumericLimits<TARGET_TYPE>::Maximum ();
33+ }
34+ return false ;
35+ }
36+ };
37+
38+ template <>
39+ double ApproxQuantileCoding::Encode (const dtime_tz_t &input) {
40+ return Encode<uint64_t , double >(input.sort_key ());
41+ }
42+
43+ template <>
44+ bool ApproxQuantileCoding::Decode (const double &source, dtime_tz_t &target) {
45+ uint64_t sort_key;
46+ const auto decoded = Decode<double , uint64_t >(source, sort_key);
47+ if (decoded) {
48+ // We can invert the sort key because its offset was not touched.
49+ auto offset = dtime_tz_t::decode_offset (sort_key);
50+ auto micros = dtime_tz_t::decode_micros (sort_key);
51+ micros -= int64_t (dtime_tz_t::encode_offset (offset) * dtime_tz_t ::OFFSET_MICROS);
52+ target = dtime_tz_t (dtime_t (micros), offset);
53+ } else if (source < 0 ) {
54+ target = Value::MinimumValue (LogicalTypeId::TIME_TZ).GetValue <dtime_tz_t >();
55+ } else {
56+ target = Value::MaximumValue (LogicalTypeId::TIME_TZ).GetValue <dtime_tz_t >();
57+ }
58+
59+ return decoded;
60+ }
61+
2062struct ApproximateQuantileBindData : public FunctionData {
2163 ApproximateQuantileBindData () {
2264 }
@@ -73,7 +115,7 @@ struct ApproxQuantileOperation {
73115
74116 template <class INPUT_TYPE , class STATE , class OP >
75117 static void Operation (STATE &state, const INPUT_TYPE &input, AggregateUnaryInput &unary_input) {
76- auto val = Cast ::template Operation <INPUT_TYPE, SAVE_TYPE>(input);
118+ auto val = ApproxQuantileCoding ::template Encode <INPUT_TYPE, SAVE_TYPE>(input);
77119 if (!Value::DoubleIsFinite (val)) {
78120 return ;
79121 }
@@ -121,15 +163,8 @@ struct ApproxQuantileScalarOperation : public ApproxQuantileOperation {
121163 state.h ->compress ();
122164 auto &bind_data = finalize_data.input .bind_data ->template Cast <ApproximateQuantileBindData>();
123165 D_ASSERT (bind_data.quantiles .size () == 1 );
124- // The result is approximate, so clamp instead of overflowing.
125166 const auto source = state.h ->quantile (bind_data.quantiles [0 ]);
126- if (TryCast::Operation (source, target, false )) {
127- return ;
128- } else if (source < 0 ) {
129- target = NumericLimits<TARGET_TYPE>::Minimum ();
130- } else {
131- target = NumericLimits<TARGET_TYPE>::Maximum ();
132- }
167+ ApproxQuantileCoding::Decode (source, target);
133168 }
134169};
135170
@@ -281,7 +316,9 @@ struct ApproxQuantileListOperation : public ApproxQuantileOperation {
281316 entry.length = bind_data.quantiles .size ();
282317 for (size_t q = 0 ; q < entry.length ; ++q) {
283318 const auto &quantile = bind_data.quantiles [q];
284- rdata[ridx + q] = Cast::template Operation<SAVE_TYPE, CHILD_TYPE>(state.h ->quantile (quantile));
319+ const auto &source = state.h ->quantile (quantile);
320+ auto &target = rdata[ridx + q];
321+ ApproxQuantileCoding::Decode (source, target);
285322 }
286323
287324 ListVector::SetListSize (finalize_data.result , entry.offset + entry.length );
0 commit comments