userver: userver/storages/postgres/io/pg_types.hpp Source File
Loading...
Searching...
No Matches
pg_types.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/storages/postgres/io/pg_types.hpp
4/// @brief Postgres-specific types I/O support
5
6#include <cstdint>
7#include <string>
8#include <string_view>
9
10#include <userver/storages/postgres/detail/db_data_type_name.hpp>
11
12USERVER_NAMESPACE_BEGIN
13
14namespace storages::postgres {
15
16/// PostgreSQL Oid type.
17// Aliased to unsigned int to match the type used in libpq.
18using Oid = unsigned int;
19inline constexpr Oid kInvalidOid = 0;
20
21//@{
22/** @name Type aliases for integral types */
23using Smallint = std::int16_t;
24using Integer = std::int32_t;
25using Bigint = std::int64_t;
26//@}
27
28//@{
29using Float4 = float;
30using Float8 = double;
31//@}
32
33/// @brief Identity for a PostgreSQL type name
34struct DBTypeName {
35 const std::string_view schema;
36 const std::string_view name;
37
38 constexpr DBTypeName()
39 : schema{},
40 name{}
41 {}
42 explicit constexpr DBTypeName(std::pair<std::string_view, std::string_view> n)
43 : schema(n.first),
44 name(n.second)
45 {}
46 /// Implicit constructor from a string literal, to enable declarations like
47 /// @code
48 /// DBTypeName my_type = "my_schema.my_type";
49 /// @endcode
50 /* implicit */ constexpr DBTypeName(const char* name)
51 : DBTypeName(utils::ParseDBName(name))
52 {}
53 constexpr DBTypeName(std::string_view s, std::string_view n)
54 : schema(s),
55 name(n)
56 {}
57
58 bool operator==(const DBTypeName& rhs) const { return name == rhs.name && schema == rhs.schema; }
59 bool operator<(const DBTypeName& rhs) const {
60 auto schema_cmp = schema.compare(rhs.schema);
61 if (schema_cmp < 0) {
62 return true;
63 } else if (schema_cmp == 0) {
64 return name < rhs.name;
65 }
66 return false;
67 }
68
69 bool Empty() const { return name.empty(); }
70 std::size_t GetHash() const;
71 std::string ToString() const;
72};
73
74/// @brief Description of a PostgreSQL type.
75/// The structure is selected from the pg_catalog.pg_type table (not all, only
76/// appropriate fields).
77/// See https://www.postgresql.org/docs/12/catalog-pg-type.html
79 enum class TypeClass : char {
80 kUnknown = 'X',
81 kBase = 'b',
82 kComposite = 'c',
83 kDomain = 'd',
84 kEnum = 'e',
85 kPseudo = 'p',
86 kRange = 'r'
87 };
88 /// @brief PosgtreSQL type category.
89 /// See
90 /// https://www.postgresql.org/docs/12/catalog-pg-type.html#CATALOG-TYPCATEGORY-TABLE
91 enum class TypeCategory : char {
92 kInvalid = 0, //!< Invalid type category
93 kArray = 'A', //!< https://www.postgresql.org/docs/12/arrays.html
94 kBoolean = 'B', //!< https://www.postgresql.org/docs/12/datatype-boolean.html
95 kComposite = 'C', //!< https://www.postgresql.org/docs/12/rowtypes.html
96 kDatetime = 'D', //!< https://www.postgresql.org/docs/12/datatype-datetime.html
97 kEnumeration = 'E', //!< https://www.postgresql.org/docs/12/datatype-enum.html
98 kGeometric = 'G', //!< https://www.postgresql.org/docs/12/datatype-geometric.html
99 kNetwork = 'I', //!< https://www.postgresql.org/docs/12/datatype-net-types.html
100 kNumeric = 'N', //!< https://www.postgresql.org/docs/12/datatype-numeric.html
101 kPseudotype = 'P', //!< https://www.postgresql.org/docs/12/datatype-pseudo.html
102 kRange = 'R', //!< https://www.postgresql.org/docs/12/rangetypes.html
103 kString = 'S', //!< https://www.postgresql.org/docs/12/datatype-character.html
104 kTimespan = 'T', //!< https://www.postgresql.org/docs/12/datatype-datetime.html
105 kUser = 'U', //!< User types, created by fourth form of create type
106 /// statement
107 /// https://www.postgresql.org/docs/12/sql-createtype.html
108 kBitstring = 'V', //!< https://www.postgresql.org/docs/12/datatype-bit.html
109 kUnknown = 'X' //!< Unknown type category
110 };
111
112 /// pg_type.oid
113 Oid oid{kInvalidOid};
114 /// pg_namespace.nspname
115 std::string schema;
116 /// pg_type.typname
117 std::string name;
118 /// pg_type.typlen
119 Integer length{0};
120 /// pg_type.typtype
121 TypeClass type_class{TypeClass::kUnknown};
122 /// pg_type.typcategory
124 /// pg_type.typrelid
125 Oid relation_id{kInvalidOid};
126 /// pg_type.typelem
127 /// If not zero, this type is an array
128 Oid element_type{kInvalidOid};
129 /// pg_type.typarray
130 Oid array_type{kInvalidOid};
131 /// pg_type.typbasetype
132 /// Base type for domains
133 Oid base_type{kInvalidOid};
134 /// pg_type.typnotnull
135 /// Used only with domains
136 bool not_null{false};
137 // TODO rest of domain fields. or eliminate them if they are not needed
138
139 DBTypeName GetName() const { return {schema.c_str(), name.c_str()}; }
140 std::size_t GetNameHash() const;
141
142 struct NameHash {
143 std::size_t operator()(const DBTypeDescription& type) const { return type.GetNameHash(); }
144 };
145 struct NamesEqual {
146 bool operator()(const DBTypeDescription& lhs, const DBTypeDescription& rhs) const {
147 return lhs.name == rhs.name && lhs.schema == rhs.schema;
148 }
149 };
151 using IntegralType = std::underlying_type_t<TypeCategory>;
152 auto operator()(TypeCategory val) const { return std::hash<IntegralType>{}(static_cast<IntegralType>(val)); }
153 };
154};
155
156/// Description of a field in a user-defined composite type, for type checking
158 Oid owner{kInvalidOid};
159 std::string name;
160 Oid type{kInvalidOid};
161
162 static CompositeFieldDef EmptyDef() { return {kInvalidOid, {}, kInvalidOid}; }
163};
164
165std::string ToString(DBTypeDescription::TypeClass);
166
167namespace io {
168/// Oids are predefined for postgres fundamental types
169/// Constants can be found here
170/// https://github.com/postgres/postgres/blob/master/src/include/catalog/pg_type.dat
171/// Oid values can also be retrieved from PostgreSQL instance by running query
172/// @code
173/// select t.oid as "Oid", pg_catalog.format_type(t.oid, null) as "Name"
174/// from pg_catalog.pg_type t
175/// left join pg_catalog.pg_namespace n on n.oid = t.typnamespace
176/// where (t.typrelid = 0 or (select c.relkind = 'c' from pg_catalog.pg_class c
177/// where c.oid = t.typrelid))
178/// and not exists(select 1 from pg_catalog.pg_type el where el.oid =
179/// t.typelem and el.typarray = t.oid) and n.nspname = 'pg_catalog'
180/// order by 1, 2
181/// @endcode
182enum class PredefinedOids {
183 kInvalid = kInvalidOid,
184 kBoolean = 16,
185 kBytea = 17,
186 kChar = 18,
187 kName = 19,
188 kInt8 = 20,
189 kInt2 = 21,
190 kInt2Vector = 22,
191 kInt4 = 23,
192 kRegproc = 24,
193 kText = 25,
194 kOid = 26,
195 kTid = 27,
196 kXid = 28,
197 kCid = 29,
198 kOidVector = 30,
199 kJson = 114,
200 kJsonArray = 199, // Not in documentation
201 kXml = 142,
202 kPgNodeTree = 194,
203 kPgDdlCommand = 32,
204 kPoint = 600,
205 kLseg = 601,
206 kPath = 602,
207 kBox = 603,
208 kPolygon = 604,
209 kLine = 628,
210 kLineArray = 629,
211 kFloat4 = 700,
212 kFloat8 = 701,
213 kAbstime = 702,
214 kReltime = 703,
215 kTinterval = 704,
216 kUnknown = 705,
217 kCircle = 718,
218 kCircleArray = 719, // Not in documentation
219 kCash = 790,
220 kMacaddr = 829,
221 kMacaddrArray = 1040,
222 kMacaddr8 = 774,
223 kMacaddr8Array = 775,
224 kInet = 869,
225 kInetArray = 1041,
226 kCidr = 650,
227 kCidrArray = 651,
228 kBooleanArray = 1000, // Not in documentation
229 kByteaArray = 1001, // Not in documentation
230 kCharArray = 1002, // Not in documentation
231 kNameArray = 1003, // Not in documentation
232 kInt2Array = 1005,
233 kInt4Array = 1007,
234 kTextArray = 1009,
235 kTidArray = 1010, // Not in documentation
236 kXidArray = 1011, // Not in documentation
237 kCidArray = 1012, // Not in documentation
238 kBphcarArray = 1014, // Not in documentation
239 kVarcharArray = 1015, // Not in documentation
240 kInt8Array = 1016, // Not in documentation
241 kPointArray = 1017, // Not in documentation
242 kLsegArray = 1018, // Not in documentation
243 kPathArray = 1019, // Not in documentation
244 kBoxArray = 1020, // Not in documentation
245 kFloat4Array = 1021,
246 kFloat8Array = 1022, // Not in documentation
247 kPolygonArray = 1027, // Not in documentation
248 kOidArray = 1028,
249 kAclItem = 1033,
250 kCstringArray = 1263,
251 kBpchar = 1042,
252 kVarchar = 1043,
253 kDate = 1082,
254 kTime = 1083,
255 kDateArray = 1182, // Not in documentation
256 kTimeArray = 1183, // Not in documentation
257 kTimestamp = 1114,
258 kTimestampArray = 1115, // Not in documentation
259 kTimestamptz = 1184,
260 kTimestamptzArray = 1185, // Not in documentation
261 kInterval = 1186,
262 kIntervalArray = 1187, // Not in documentation
263 kNumericArray = 1231, // Not in documentation
264 kTimetz = 1266,
265 kBit = 1560,
266 kBitArray = 1561,
267 kVarbit = 1562,
268 kVarbitArray = 1563,
269 kNumeric = 1700,
270 kRefcursor = 1790,
271 kRegprocedure = 2202,
272 kRegoper = 2203,
273 kRegoperator = 2204,
274 kRegclass = 2205,
275 kRegtype = 2206,
276 kRegrole = 4096,
277 kRegtypearray = 2211,
278 kUuid = 2950,
279 kUuidArray = 2951, // Not in documentation
280 kLsn = 3220,
281 kLsnArray = 3221,
282 kTsvector = 3614,
283 kGtsvector = 3642,
284 kTsquery = 3615,
285 kRegconfig = 3734,
286 kRegdictionary = 3769,
287 kJsonb = 3802,
288 kJsonbArray = 3807, // Not in documentation
289 kRecord = 2249,
290 kRecordArray = 2287,
291 kCstring = 2275,
292 kAny = 2276,
293 kAnyArray = 2277,
294 kVoid = 2278,
295 kTrigger = 2279,
296 kEvttrigger = 3838,
297 kLanguageHandler = 2280,
298 kInternal = 2281,
299 kOpaque = 2282,
300 kAnyElement = 2283,
301 kAnyNonArray = 2776,
302 kAnyEnum = 3500,
303 kFdwHandler = 3115,
304 kAnyRange = 3831,
305 kInt4Range = 3904,
306 kInt4RangeArray = 3905, // Not in documentation
307 kNumRange = 3906, // Not in documentation
308 kNumRangeArray = 3907, // Not in documentation
309 kTimestampRange = 3908, // Not in documentation
310 kTimestampRangeArray = 3909, // Not in documentation
311 kTimestamptzRange = 3910, // Not in documentation
312 kTimestamptzRangeArray = 3911, // Not in documentation
313 kDateRange = 3912, // Not in documentation
314 kDateRangeArray = 3913, // Not in documentation
315 kInt8Range = 3926, // Not in documentation
316 kInt8RangeArray = 3927, // Not in documentation
317};
318
319template <PredefinedOids TypeOid>
320using PredefinedOid = std::integral_constant<PredefinedOids, TypeOid>;
321
322//@{
323/** @name Array types for predefined oids */
324template <PredefinedOids TypeOid>
325struct ArrayType : PredefinedOid<PredefinedOids::kInvalid> {};
326
327template <>
328struct ArrayType<PredefinedOids::kBoolean> : PredefinedOid<PredefinedOids::kBooleanArray> {};
329template <>
330struct ArrayType<PredefinedOids::kBytea> : PredefinedOid<PredefinedOids::kByteaArray> {};
331template <>
332struct ArrayType<PredefinedOids::kChar> : PredefinedOid<PredefinedOids::kCharArray> {};
333template <>
334struct ArrayType<PredefinedOids::kName> : PredefinedOid<PredefinedOids::kNameArray> {};
335template <>
336struct ArrayType<PredefinedOids::kInt2> : PredefinedOid<PredefinedOids::kInt2Array> {};
337template <>
338struct ArrayType<PredefinedOids::kInt4> : PredefinedOid<PredefinedOids::kInt4Array> {};
339template <>
340struct ArrayType<PredefinedOids::kInt8> : PredefinedOid<PredefinedOids::kInt8Array> {};
341template <>
342struct ArrayType<PredefinedOids::kText> : PredefinedOid<PredefinedOids::kTextArray> {};
343template <>
344struct ArrayType<PredefinedOids::kOid> : PredefinedOid<PredefinedOids::kOidArray> {};
345template <>
346struct ArrayType<PredefinedOids::kCidr> : PredefinedOid<PredefinedOids::kCidArray> {};
347template <>
348struct ArrayType<PredefinedOids::kInet> : PredefinedOid<PredefinedOids::kInetArray> {};
349template <>
350struct ArrayType<PredefinedOids::kTid> : PredefinedOid<PredefinedOids::kTidArray> {};
351template <>
352struct ArrayType<PredefinedOids::kXid> : PredefinedOid<PredefinedOids::kXidArray> {};
353template <>
354struct ArrayType<PredefinedOids::kCid> : PredefinedOid<PredefinedOids::kCidArray> {};
355template <>
356struct ArrayType<PredefinedOids::kLsn> : PredefinedOid<PredefinedOids::kLsnArray> {};
357
358template <>
359struct ArrayType<PredefinedOids::kFloat4> : PredefinedOid<PredefinedOids::kFloat4Array> {};
360template <>
361struct ArrayType<PredefinedOids::kFloat8> : PredefinedOid<PredefinedOids::kFloat8Array> {};
362
363template <>
364struct ArrayType<PredefinedOids::kBpchar> : PredefinedOid<PredefinedOids::kBphcarArray> {};
365template <>
366struct ArrayType<PredefinedOids::kVarchar> : PredefinedOid<PredefinedOids::kVarcharArray> {};
367
368template <>
369struct ArrayType<PredefinedOids::kDate> : PredefinedOid<PredefinedOids::kDateArray> {};
370
371template <>
372struct ArrayType<PredefinedOids::kTime> : PredefinedOid<PredefinedOids::kTimeArray> {};
373
374template <>
375struct ArrayType<PredefinedOids::kTimestamp> : PredefinedOid<PredefinedOids::kTimestampArray> {};
376template <>
377struct ArrayType<PredefinedOids::kTimestamptz> : PredefinedOid<PredefinedOids::kTimestamptzArray> {};
378
379template <>
380struct ArrayType<PredefinedOids::kInterval> : PredefinedOid<PredefinedOids::kIntervalArray> {};
381
382template <>
383struct ArrayType<PredefinedOids::kBit> : PredefinedOid<PredefinedOids::kBitArray> {};
384
385template <>
386struct ArrayType<PredefinedOids::kVarbit> : PredefinedOid<PredefinedOids::kVarbitArray> {};
387
388template <>
389struct ArrayType<PredefinedOids::kNumeric> : PredefinedOid<PredefinedOids::kNumericArray> {};
390
391template <>
392struct ArrayType<PredefinedOids::kUuid> : PredefinedOid<PredefinedOids::kUuidArray> {};
393
394template <>
395struct ArrayType<PredefinedOids::kInt4Range> : PredefinedOid<PredefinedOids::kInt4RangeArray> {};
396
397template <>
398struct ArrayType<PredefinedOids::kNumRange> : PredefinedOid<PredefinedOids::kNumRangeArray> {};
399
400template <>
401struct ArrayType<PredefinedOids::kTimestampRange> : PredefinedOid<PredefinedOids::kTimestampRangeArray> {};
402
403template <>
404struct ArrayType<PredefinedOids::kTimestamptzRange> : PredefinedOid<PredefinedOids::kTimestamptzRangeArray> {};
405
406template <>
407struct ArrayType<PredefinedOids::kDateRange> : PredefinedOid<PredefinedOids::kDateRangeArray> {};
408
409template <>
410struct ArrayType<PredefinedOids::kInt8Range> : PredefinedOid<PredefinedOids::kInt8RangeArray> {};
411
412template <>
413struct ArrayType<PredefinedOids::kPoint> : PredefinedOid<PredefinedOids::kPointArray> {};
414template <>
415struct ArrayType<PredefinedOids::kLseg> : PredefinedOid<PredefinedOids::kLsegArray> {};
416template <>
417struct ArrayType<PredefinedOids::kLine> : PredefinedOid<PredefinedOids::kLineArray> {};
418template <>
419struct ArrayType<PredefinedOids::kBox> : PredefinedOid<PredefinedOids::kBoxArray> {};
420template <>
421struct ArrayType<PredefinedOids::kPath> : PredefinedOid<PredefinedOids::kPathArray> {};
422template <>
423struct ArrayType<PredefinedOids::kPolygon> : PredefinedOid<PredefinedOids::kPolygonArray> {};
424template <>
425struct ArrayType<PredefinedOids::kCircle> : PredefinedOid<PredefinedOids::kCircleArray> {};
426
427template <>
428struct ArrayType<PredefinedOids::kJson> : PredefinedOid<PredefinedOids::kJsonArray> {};
429template <>
430struct ArrayType<PredefinedOids::kJsonb> : PredefinedOid<PredefinedOids::kJsonbArray> {};
431
432template <>
433struct ArrayType<PredefinedOids::kRecord> : PredefinedOid<PredefinedOids::kRecordArray> {};
434
435template <>
436struct ArrayType<PredefinedOids::kMacaddr> : PredefinedOid<PredefinedOids::kMacaddrArray> {};
437
438template <>
439struct ArrayType<PredefinedOids::kMacaddr8> : PredefinedOid<PredefinedOids::kMacaddr8Array> {};
440
441//@}
442
443} // namespace io
444} // namespace storages::postgres
445
446USERVER_NAMESPACE_END
447
448namespace std {
449
450template <>
451struct hash<USERVER_NAMESPACE::storages::postgres::io::PredefinedOids> {
452 std::size_t operator()(USERVER_NAMESPACE::storages::postgres::io::PredefinedOids value) const {
453 return static_cast<std::size_t>(value);
454 }
455};
456
457template <>
458struct hash<USERVER_NAMESPACE::storages::postgres::DBTypeName> {
459 std::size_t operator()(const USERVER_NAMESPACE::storages::postgres::DBTypeName& value) const {
460 return value.GetHash();
461 }
462};
463
464} // namespace std