forked from ClickHouse/ClickHouse
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDataTypeFixedString.cpp
More file actions
194 lines (139 loc) · 5.65 KB
/
Copy pathDataTypeFixedString.cpp
File metadata and controls
194 lines (139 loc) · 5.65 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
#include <Columns/ColumnFixedString.h>
#include <Common/Exception.h>
#include <Common/SipHash.h>
#include <DataTypes/DataTypeFixedString.h>
#include <DataTypes/DataTypeFactory.h>
#include <DataTypes/Serializations/SerializationFixedString.h>
#include <IO/WriteHelpers.h>
#include <Parsers/IAST.h>
#include <Parsers/ASTLiteral.h>
namespace DB
{
namespace ErrorCodes
{
extern const int ARGUMENT_OUT_OF_BOUND;
extern const int NUMBER_OF_ARGUMENTS_DOESNT_MATCH;
extern const int UNEXPECTED_AST_STRUCTURE;
}
DataTypeFixedString::DataTypeFixedString(size_t n_) : n(n_)
{
if (n == 0)
throw Exception(ErrorCodes::ARGUMENT_OUT_OF_BOUND, "FixedString size must be positive");
if (n > MAX_FIXEDSTRING_SIZE)
throw Exception(ErrorCodes::ARGUMENT_OUT_OF_BOUND, "FixedString size is too large");
}
std::string DataTypeFixedString::doGetName() const
{
return "FixedString(" + toString(n) + ")";
}
MutableColumnPtr DataTypeFixedString::createColumn() const
{
return ColumnFixedString::create(n);
}
Field DataTypeFixedString::getDefault() const
{
return String();
}
bool DataTypeFixedString::equals(const IDataType & rhs) const
{
return typeid(rhs) == typeid(*this) && n == static_cast<const DataTypeFixedString &>(rhs).n;
}
void DataTypeFixedString::updateHashImpl(SipHash & hash) const
{
hash.update(n);
}
SerializationPtr DataTypeFixedString::doGetSerialization(const SerializationInfoSettings &) const
{
return SerializationFixedString::create(n);
}
static DataTypePtr create(const ASTPtr & arguments)
{
if (!arguments || arguments->children.size() != 1)
throw Exception(ErrorCodes::NUMBER_OF_ARGUMENTS_DOESNT_MATCH,
"FixedString data type family must have exactly one argument - size in bytes");
const auto * argument = arguments->children[0]->as<ASTLiteral>();
if (!argument || argument->value.getType() != Field::Types::UInt64 || argument->value.safeGet<UInt64>() == 0)
throw Exception(ErrorCodes::UNEXPECTED_AST_STRUCTURE,
"FixedString data type family must have a number (positive integer) as its argument");
return std::make_shared<DataTypeFixedString>(argument->value.safeGet<UInt64>());
}
void registerDataTypeFixedString(DataTypeFactory & factory)
{
factory.registerDataType("FixedString", create, DataTypeFactory::Case::Sensitive,
Documentation{
.description = R"DOCS_MD(
A fixed-length string of `N` bytes (neither characters nor code points).
To declare a column of `FixedString` type, use the following syntax:
```sql
<column_name> FixedString(N)
```
Where `N` is a natural number.
The `FixedString` type is efficient when data has the length of precisely `N` bytes. In all other cases, it is likely to reduce efficiency.
Examples of the values that can be efficiently stored in `FixedString`-typed columns:
- The binary representation of IP addresses (`FixedString(16)` for IPv6).
- Language codes (ru_RU, en_US, ...).
- Currency codes (USD, RUB, ...).
- Binary representation of hashes (`FixedString(16)` for MD5, `FixedString(32)` for SHA256).
To store UUID values, use the [UUID](../../sql-reference/data-types/uuid.md) data type.
When inserting the data, ClickHouse:
- Complements a string with null bytes if the string contains fewer than `N` bytes.
- Throws the `Too large value for FixedString(N)` exception if the string contains more than `N` bytes.
Let's consider the following table with the single `FixedString(2)` column:
```sql
INSERT INTO FixedStringTable VALUES ('a'), ('ab'), ('');
```
```sql
SELECT
name,
toTypeName(name),
length(name),
empty(name)
FROM FixedStringTable;
```
```text
┌─name─┬─toTypeName(name)─┬─length(name)─┬─empty(name)─┐
│ a │ FixedString(2) │ 2 │ 0 │
│ ab │ FixedString(2) │ 2 │ 0 │
│ │ FixedString(2) │ 2 │ 1 │
└──────┴──────────────────┴──────────────┴─────────────┘
```
Note that the length of the `FixedString(N)` value is constant. The [length](/sql-reference/functions/array-functions#length) function returns `N` even if the `FixedString(N)` value is filled only with null bytes, but the [empty](/sql-reference/functions/array-functions#empty) function returns `1` in this case.
Selecting data with `WHERE` clause return various result depending on how the condition is specified:
- If equality operator `=` or `==` or `equals` function used, ClickHouse _doesn't_ take `\0` char into consideration, i.e. queries `SELECT * FROM FixedStringTable WHERE name = 'a';` and `SELECT * FROM FixedStringTable WHERE name = 'a\0';` return the same result.
- If `LIKE` clause is used, ClickHouse _does_ take `\0` char into consideration, so one may need to explicitly specify `\0` char in the filter condition.
```sql
SELECT name
FROM FixedStringTable
WHERE name = 'a'
FORMAT JSONStringsEachRow
{"name":"a\u0000"}
SELECT name
FROM FixedStringTable
WHERE name = 'a\0'
FORMAT JSONStringsEachRow
{"name":"a\u0000"}
SELECT name
FROM FixedStringTable
WHERE name = 'a'
FORMAT JSONStringsEachRow
Query id: c32cec28-bb9e-4650-86ce-d74a1694d79e
{"name":"a\u0000"}
SELECT name
FROM FixedStringTable
WHERE name LIKE 'a'
FORMAT JSONStringsEachRow
0 rows in set.
SELECT name
FROM FixedStringTable
WHERE name LIKE 'a\0'
FORMAT JSONStringsEachRow
{"name":"a\u0000"}
```
)DOCS_MD",
.syntax = "FixedString(N)",
.related = {"String"},
});
/// Compatibility alias.
factory.registerAlias("BINARY", "FixedString", DataTypeFactory::Case::Insensitive);
}
}