22
33#include " string.h"
44#include " nullable.h"
5+ #include " numeric.h"
6+ #include " enum.h"
7+ #include " date.h"
8+ #include " ip4.h"
9+ #include " ip6.h"
10+ #include " uuid.h"
11+ #include " ../base/socket.h" // for htonl/ntohl and in_addr/in6_addr
512#include " ../base/wire_format.h"
613
714#include < city.h>
1017#include < string_view>
1118#include < type_traits>
1219#include < cmath>
20+ #include < cstring>
1321
1422#include < cassert>
1523
@@ -78,30 +86,60 @@ inline ResultColumnType & column_down_cast(ColumnType & c) {
7886 return dynamic_cast <ResultColumnType &>(c);
7987}
8088
81- // std::visit-ish function to avoid including <variant> header, which is not present in older version of XCode.
82- template <typename Vizitor, typename ColumnType>
83- inline auto VisitIndexColumn (Vizitor && vizitor, ColumnType && col) {
84- switch (col.Type ()->GetCode ()) {
89+ // Number of bytes an ItemView holds for a fixed-size dictionary type, or 0 for
90+ // variable-size (String/FixedString) or unsupported types. Used to build a
91+ // correctly-sized zero value for the default/null dictionary item.
92+ inline size_t FixedSizeForDictionaryType (Type::Code code) {
93+ switch (code) {
94+ case Type::Int8:
8595 case Type::UInt8:
86- return vizitor (column_down_cast<ColumnUInt8>(col));
96+ return 1 ;
97+ case Type::Int16:
8798 case Type::UInt16:
88- return vizitor (column_down_cast<ColumnUInt16>(col));
99+ case Type::Date:
100+ return 2 ;
101+ case Type::Int32:
89102 case Type::UInt32:
90- return vizitor (column_down_cast<ColumnUInt32>(col));
103+ case Type::Float32:
104+ case Type::DateTime:
105+ case Type::Date32:
106+ case Type::IPv4:
107+ return 4 ;
108+ case Type::Int64:
91109 case Type::UInt64:
92- return vizitor (column_down_cast<ColumnUInt64>(col));
110+ case Type::Float64:
111+ return 8 ;
112+ case Type::Int128:
113+ case Type::UInt128:
114+ case Type::IPv6:
115+ case Type::UUID :
116+ return 16 ;
93117 default :
94- throw ValidationError ( " Invalid index column type " + col. GetType (). GetName ()) ;
118+ return 0 ;
95119 }
96120}
97121
122+ // A zero-filled, correctly-sized ItemView for a fixed-size dictionary type. The
123+ // backing buffer is static so the non-owning view stays valid.
124+ inline ItemView ZeroItemForDictionary (Type::Code code) {
125+ if (const auto size = FixedSizeForDictionaryType (code)) {
126+ static const char zeros[16 ] = {};
127+ if (size > sizeof (zeros)) {
128+ throw AssertionError (" The size of item view for ColumnLowCardinality exceeds the buffer size" );
129+ }
130+ return ItemView{code, std::string_view{zeros, size}};
131+ }
132+ // Variable-size types (String/FixedString) accept an empty value.
133+ return ItemView{code, std::string_view{}};
134+ }
135+
98136// A special NULL-item, which is expected at pos(0) in dictionary,
99137// note that we distinguish empty string from NULL-value.
100138inline auto GetNullItemForDictionary (const ColumnRef dictionary) {
101139 if (auto n = dictionary->As <ColumnNullable>()) {
102140 return ItemView {};
103141 } else {
104- return ItemView{ dictionary->Type ()->GetCode (), std::string_view{}} ;
142+ return ZeroItemForDictionary ( dictionary->Type ()->GetCode ()) ;
105143 }
106144}
107145
@@ -111,7 +149,7 @@ inline ItemView GetDefaultItemForDictionary(const ColumnRef dictionary) {
111149 if (auto n = dictionary->As <ColumnNullable>()) {
112150 return GetDefaultItemForDictionary (n->Nested ());
113151 } else {
114- return ItemView{ dictionary->Type ()->GetCode (), std::string_view{}} ;
152+ return ZeroItemForDictionary ( dictionary->Type ()->GetCode ()) ;
115153 }
116154}
117155
@@ -147,6 +185,72 @@ inline void AppendToDictionary(Column& dictionary, const ItemView & item) {
147185 case Type::Nullable:
148186 AppendNullableToDictionary (column_down_cast<ColumnNullable>(dictionary), item);
149187 return ;
188+ // Fixed-size dictionary types. The ItemView holds the raw stored bytes
189+ // (see the matching ColumnXxx::GetItem), so we re-append the raw value.
190+ case Type::Int8:
191+ column_down_cast<ColumnInt8>(dictionary).Append (item.get <int8_t >());
192+ return ;
193+ case Type::Int16:
194+ column_down_cast<ColumnInt16>(dictionary).Append (item.get <int16_t >());
195+ return ;
196+ case Type::Int32:
197+ column_down_cast<ColumnInt32>(dictionary).Append (item.get <int32_t >());
198+ return ;
199+ case Type::Int64:
200+ column_down_cast<ColumnInt64>(dictionary).Append (item.get <int64_t >());
201+ return ;
202+ case Type::UInt8:
203+ column_down_cast<ColumnUInt8>(dictionary).Append (item.get <uint8_t >());
204+ return ;
205+ case Type::UInt16:
206+ column_down_cast<ColumnUInt16>(dictionary).Append (item.get <uint16_t >());
207+ return ;
208+ case Type::UInt32:
209+ column_down_cast<ColumnUInt32>(dictionary).Append (item.get <uint32_t >());
210+ return ;
211+ case Type::UInt64:
212+ column_down_cast<ColumnUInt64>(dictionary).Append (item.get <uint64_t >());
213+ return ;
214+ case Type::Int128:
215+ column_down_cast<ColumnInt128>(dictionary).Append (item.get <Int128>());
216+ return ;
217+ case Type::UInt128:
218+ column_down_cast<ColumnUInt128>(dictionary).Append (item.get <UInt128>());
219+ return ;
220+ case Type::Float32:
221+ column_down_cast<ColumnFloat32>(dictionary).Append (item.get <float >());
222+ return ;
223+ case Type::Float64:
224+ column_down_cast<ColumnFloat64>(dictionary).Append (item.get <double >());
225+ return ;
226+ case Type::Date:
227+ column_down_cast<ColumnDate>(dictionary).AppendRaw (item.get <uint16_t >());
228+ return ;
229+ case Type::Date32:
230+ column_down_cast<ColumnDate32>(dictionary).AppendRaw (item.get <int32_t >());
231+ return ;
232+ case Type::DateTime:
233+ column_down_cast<ColumnDateTime>(dictionary).AppendRaw (item.get <uint32_t >());
234+ return ;
235+ case Type::IPv4:
236+ // ColumnIPv4::Append applies htonl, and GetItem returns the stored
237+ // (already byte-swapped) value, so undo the swap to re-store as-is.
238+ column_down_cast<ColumnIPv4>(dictionary).Append (ntohl (item.get <uint32_t >()));
239+ return ;
240+ case Type::IPv6: {
241+ in6_addr addr;
242+ std::memcpy (&addr, item.data .data (), sizeof (addr));
243+ column_down_cast<ColumnIPv6>(dictionary).Append (addr);
244+ return ;
245+ }
246+ case Type::UUID : {
247+ UUID value;
248+ std::memcpy (&value.first , item.data .data (), sizeof (value.first ));
249+ std::memcpy (&value.second , item.data .data () + sizeof (value.first ),
250+ sizeof (value.second ));
251+ column_down_cast<ColumnUUID>(dictionary).Append (value);
252+ return ;
253+ }
150254 default :
151255 throw ValidationError (" Unexpected dictionary column type: " + dictionary.GetType ().GetName ());
152256 }
0 commit comments