1#pragma once
2
3#include <Columns/IColumn.h>
4#include <Columns/IColumnImpl.h>
5#include <Columns/ColumnsNumber.h>
6#include <Common/typeid_cast.h>
7#include <Common/assert_cast.h>
8
9
10namespace DB
11{
12
13using NullMap = ColumnUInt8::Container;
14using ConstNullMapPtr = const NullMap *;
15
16/// Class that specifies nullable columns. A nullable column represents
17/// a column, which may have any type, provided with the possibility of
18/// storing NULL values. For this purpose, a ColumNullable object stores
19/// an ordinary column along with a special column, namely a byte map,
20/// whose type is ColumnUInt8. The latter column indicates whether the
21/// value of a given row is a NULL or not. Such a design is preferred
22/// over a bitmap because columns are usually stored on disk as compressed
23/// files. In this regard, using a bitmap instead of a byte map would
24/// greatly complicate the implementation with little to no benefits.
25class ColumnNullable final : public COWHelper<IColumn, ColumnNullable>
26{
27private:
28 friend class COWHelper<IColumn, ColumnNullable>;
29
30 ColumnNullable(MutableColumnPtr && nested_column_, MutableColumnPtr && null_map_);
31 ColumnNullable(const ColumnNullable &) = default;
32
33public:
34 /** Create immutable column using immutable arguments. This arguments may be shared with other columns.
35 * Use IColumn::mutate in order to make mutable column and mutate shared nested columns.
36 */
37 using Base = COWHelper<IColumn, ColumnNullable>;
38 static Ptr create(const ColumnPtr & nested_column_, const ColumnPtr & null_map_)
39 {
40 return ColumnNullable::create(nested_column_->assumeMutable(), null_map_->assumeMutable());
41 }
42
43 template <typename ... Args, typename = typename std::enable_if<IsMutableColumns<Args ...>::value>::type>
44 static MutablePtr create(Args &&... args) { return Base::create(std::forward<Args>(args)...); }
45
46 const char * getFamilyName() const override { return "Nullable"; }
47 std::string getName() const override { return "Nullable(" + nested_column->getName() + ")"; }
48 MutableColumnPtr cloneResized(size_t size) const override;
49 size_t size() const override { return nested_column->size(); }
50 bool isNullAt(size_t n) const override { return assert_cast<const ColumnUInt8 &>(*null_map).getData()[n] != 0;}
51 Field operator[](size_t n) const override;
52 void get(size_t n, Field & res) const override;
53 bool getBool(size_t n) const override { return isNullAt(n) ? 0 : nested_column->getBool(n); }
54 UInt64 get64(size_t n) const override { return nested_column->get64(n); }
55 StringRef getDataAt(size_t n) const override;
56
57 /// Will insert null value if pos=nullptr
58 void insertData(const char * pos, size_t length) override;
59 StringRef serializeValueIntoArena(size_t n, Arena & arena, char const *& begin) const override;
60 const char * deserializeAndInsertFromArena(const char * pos) override;
61 void insertRangeFrom(const IColumn & src, size_t start, size_t length) override;
62 void insert(const Field & x) override;
63 void insertFrom(const IColumn & src, size_t n) override;
64
65 void insertFromNotNullable(const IColumn & src, size_t n);
66 void insertRangeFromNotNullable(const IColumn & src, size_t start, size_t length);
67 void insertManyFromNotNullable(const IColumn & src, size_t position, size_t length);
68
69 void insertDefault() override
70 {
71 getNestedColumn().insertDefault();
72 getNullMapData().push_back(1);
73 }
74
75 void popBack(size_t n) override;
76 ColumnPtr filter(const Filter & filt, ssize_t result_size_hint) const override;
77 ColumnPtr permute(const Permutation & perm, size_t limit) const override;
78 ColumnPtr index(const IColumn & indexes, size_t limit) const override;
79 int compareAt(size_t n, size_t m, const IColumn & rhs_, int null_direction_hint) const override;
80 void getPermutation(bool reverse, size_t limit, int null_direction_hint, Permutation & res) const override;
81 void reserve(size_t n) override;
82 size_t byteSize() const override;
83 size_t allocatedBytes() const override;
84 void protect() override;
85 ColumnPtr replicate(const Offsets & replicate_offsets) const override;
86 void updateHashWithValue(size_t n, SipHash & hash) const override;
87 void getExtremes(Field & min, Field & max) const override;
88
89 MutableColumns scatter(ColumnIndex num_columns, const Selector & selector) const override
90 {
91 return scatterImpl<ColumnNullable>(num_columns, selector);
92 }
93
94 void gather(ColumnGathererStream & gatherer_stream) override;
95
96 void forEachSubcolumn(ColumnCallback callback) override
97 {
98 callback(nested_column);
99 callback(null_map);
100 }
101
102 bool structureEquals(const IColumn & rhs) const override
103 {
104 if (auto rhs_nullable = typeid_cast<const ColumnNullable *>(&rhs))
105 return nested_column->structureEquals(*rhs_nullable->nested_column);
106 return false;
107 }
108
109 bool isNullable() const override { return true; }
110 bool isFixedAndContiguous() const override { return false; }
111 bool valuesHaveFixedSize() const override { return nested_column->valuesHaveFixedSize(); }
112 size_t sizeOfValueIfFixed() const override { return null_map->sizeOfValueIfFixed() + nested_column->sizeOfValueIfFixed(); }
113 bool onlyNull() const override { return nested_column->isDummy(); }
114
115
116 /// Return the column that represents values.
117 IColumn & getNestedColumn() { return *nested_column; }
118 const IColumn & getNestedColumn() const { return *nested_column; }
119
120 const ColumnPtr & getNestedColumnPtr() const { return nested_column; }
121
122 /// Return the column that represents the byte map.
123 const ColumnPtr & getNullMapColumnPtr() const { return null_map; }
124
125 ColumnUInt8 & getNullMapColumn() { return assert_cast<ColumnUInt8 &>(*null_map); }
126 const ColumnUInt8 & getNullMapColumn() const { return assert_cast<const ColumnUInt8 &>(*null_map); }
127
128 NullMap & getNullMapData() { return getNullMapColumn().getData(); }
129 const NullMap & getNullMapData() const { return getNullMapColumn().getData(); }
130
131 /// Apply the null byte map of a specified nullable column onto the
132 /// null byte map of the current column by performing an element-wise OR
133 /// between both byte maps. This method is used to determine the null byte
134 /// map of the result column of a function taking one or more nullable
135 /// columns.
136 void applyNullMap(const ColumnNullable & other);
137 void applyNullMap(const ColumnUInt8 & map);
138 void applyNegatedNullMap(const ColumnUInt8 & map);
139
140 /// Check that size of null map equals to size of nested column.
141 void checkConsistency() const;
142
143private:
144 WrappedPtr nested_column;
145 WrappedPtr null_map;
146
147 template <bool negative>
148 void applyNullMapImpl(const ColumnUInt8 & map);
149};
150
151ColumnPtr makeNullable(const ColumnPtr & column);
152
153}
154