Cppgres
Build Postgres extensions in C++
Loading...
Searching...
No Matches
types.hpp
Go to the documentation of this file.
1
4#pragma once
5
6#include <optional>
7#include <string>
8#include <utility>
9
10#include "datum.hpp"
11#include "syscache.hpp"
12#include "type.hpp"
13
14namespace cppgres {
15
16template <> struct type_traits<void *> {
17 bool is(const type &t) { return t.oid == INTERNALOID; }
18 constexpr type type_for() { return type{.oid = INTERNALOID}; }
19};
20
21template <> struct type_traits<void> {
22 bool is(const type &t) { return t.oid == VOIDOID; }
23 constexpr type type_for() { return type{.oid = VOIDOID}; }
24};
25
26template <> struct type_traits<oid> {
27 static bool is(const type &t) { return t.oid == OIDOID; }
28 static constexpr type type_for() { return type{.oid = OIDOID}; }
29};
30
31template <> struct type_traits<nullable_datum> {
32 static bool is(const type &t) { return true; }
33 static constexpr type type_for() { return type{.oid = ANYOID}; }
34};
35
36template <> struct type_traits<datum> {
37 static bool is(const type &t) { return true; }
38 static constexpr type type_for() { return type{.oid = ANYOID}; }
39};
40
41template <typename S> struct type_traits<S, std::enable_if_t<utils::is_std_tuple<S>::value>> {
42 bool is(const type &t) {
43 if (t.oid == RECORDOID) {
44 return true;
45 } else if constexpr (std::tuple_size_v<S> == 1) {
46 // special case when we have a tuple of 1 matching the type
48 }
49 return false;
50 }
51 constexpr type type_for() { return type{.oid = RECORDOID}; }
52};
53
54template <> struct type_traits<bool> {
55 type_traits() {}
56 type_traits(const bool &) {}
57 bool is(const type &t) { return t.oid == BOOLOID; }
58 constexpr type type_for() { return type{.oid = BOOLOID}; }
59};
60
61template <> struct type_traits<int64_t> {
62 type_traits() {}
63 type_traits(const int64_t &) {}
64 bool is(const type &t) { return t.oid == INT8OID || t.oid == INT4OID || t.oid == INT2OID; }
65 constexpr type type_for() { return type{.oid = INT8OID}; }
66};
67
68template <> struct type_traits<int32_t> {
69 type_traits() {}
70 type_traits(const int32_t &) {}
71 bool is(const type &t) { return t.oid == INT4OID || t.oid == INT2OID; }
72 constexpr type type_for() { return type{.oid = INT4OID}; }
73};
74
75template <> struct type_traits<int16_t> {
76 type_traits() {}
77 type_traits(const int16_t &) {}
78 bool is(const type &t) { return t.oid == INT2OID; }
79 constexpr type type_for() { return type{.oid = INT2OID}; }
80};
81
82template <> struct type_traits<int8_t> {
83 type_traits() {}
84 type_traits(const int8_t &) {}
85 bool is(const type &t) { return t.oid == INT2OID; }
86 constexpr type type_for() { return type{.oid = INT2OID}; }
87};
88
89template <> struct type_traits<double> {
90 type_traits() {}
91 type_traits(const double &) {}
92 bool is(const type &t) { return t.oid == FLOAT8OID || t.oid == FLOAT4OID; }
93 constexpr type type_for() { return type{.oid = FLOAT8OID}; }
94};
95
96template <> struct type_traits<float> {
97 type_traits() {}
98 type_traits(const float &) {}
99 bool is(const type &t) { return t.oid == FLOAT4OID; }
100 constexpr type type_for() { return type{.oid = FLOAT4OID}; }
101};
102
103template <> struct type_traits<text> {
104 type_traits() {}
105 type_traits(const text &) {}
106 bool is(const type &t) { return t.oid == TEXTOID; }
107 constexpr type type_for() { return type{.oid = TEXTOID}; }
108};
109
110template <> struct type_traits<std::string_view> {
111 type_traits() {}
112 type_traits(const std::string_view &) {}
113 bool is(const type &t) { return t.oid == TEXTOID; }
114 constexpr type type_for() { return type{.oid = TEXTOID}; }
115};
116
117template <> struct type_traits<std::string> {
118 type_traits() {}
119 type_traits(const std::string &) {}
120 bool is(const type &t) { return t.oid == TEXTOID; }
121 constexpr type type_for() { return type{.oid = TEXTOID}; }
122};
123
124template <> struct type_traits<byte_array> {
125 type_traits() {}
126 type_traits(const byte_array &) {}
127 bool is(const type &t) { return t.oid == BYTEAOID; }
128 constexpr type type_for() { return type{.oid = BYTEAOID}; }
129};
130
131template <> struct type_traits<bytea> {
132 type_traits() {}
133 type_traits(const bytea &) {}
134 bool is(const type &t) { return t.oid == BYTEAOID; }
135 constexpr type type_for() { return type{.oid = BYTEAOID}; }
136};
137
138template <> struct type_traits<char *> {
139 type_traits() {}
140 type_traits(const char *&) {}
141 bool is(const type &t) { return t.oid == CSTRINGOID; }
142 constexpr type type_for() { return type{.oid = CSTRINGOID}; }
143};
144
145template <> struct type_traits<const char *> {
146 type_traits() {}
147 type_traits(const char *&) {}
148 bool is(const type &t) { return t.oid == CSTRINGOID; }
149 constexpr type type_for() { return type{.oid = CSTRINGOID}; }
150};
151
152template <std::size_t N> struct type_traits<const char[N]> {
153 type_traits() {}
154 type_traits(const char (&)[N]) {}
155 bool is(const type &t) { return t.oid == CSTRINGOID; }
156 constexpr type type_for() { return type{.oid = CSTRINGOID}; }
157};
158
159template <flattenable F> struct type_traits<expanded_varlena<F>> {
160 type_traits() {}
162 bool is(const type &t) { return t.oid == F::type().oid; }
163 constexpr type type_for() { return F::type(); }
164};
165
166template <> struct datum_conversion<datum> : default_datum_conversion<datum> {
167 static datum from_datum(const datum &d, oid, std::optional<memory_context>) { return d; }
168
169 static datum into_datum(const datum &t) { return t; }
170};
171
172template <> struct datum_conversion<nullable_datum> : default_datum_conversion<nullable_datum> {
173 static nullable_datum from_datum(const datum &d, oid, std::optional<memory_context>) {
174 return nullable_datum(d);
175 }
176
177 static datum into_datum(const nullable_datum &t) { return t.is_null() ? datum(0) : t; }
178};
179
181 static void *from_datum(const datum &d, oid, std::optional<memory_context>) {
182 return reinterpret_cast<void *>(d.operator const ::Datum &());
183 }
184
185 static datum into_datum(const void *const &t) { return datum(reinterpret_cast<::Datum>(t)); }
186};
187
189 static oid from_datum(const datum &d, oid, std::optional<memory_context>) {
190 return static_cast<oid>(d.operator const ::Datum &());
191 }
192
193 static datum into_datum(const oid &t) { return datum(static_cast<::Datum>(t)); }
194};
195
196template <> struct datum_conversion<size_t> : default_datum_conversion<size_t> {
197 static size_t from_datum(const datum &d, oid, std::optional<memory_context>) {
198 return static_cast<size_t>(d.operator const ::Datum &());
199 }
200
201 static datum into_datum(const size_t &t) { return datum(static_cast<::Datum>(t)); }
202};
203
204template <> struct datum_conversion<int64_t> : default_datum_conversion<int64_t> {
205 static int64_t from_datum(const datum &d, oid, std::optional<memory_context>) {
206 return static_cast<int64_t>(d.operator const ::Datum &());
207 }
208
209 static datum into_datum(const int64_t &t) { return datum(static_cast<::Datum>(t)); }
210};
211
212template <> struct datum_conversion<int32_t> : default_datum_conversion<int32_t> {
213 static int32_t from_datum(const datum &d, oid, std::optional<memory_context>) {
214 return static_cast<int32_t>(d.operator const ::Datum &());
215 }
216 static datum into_datum(const int32_t &t) { return datum(static_cast<::Datum>(t)); }
217};
218
219template <> struct datum_conversion<int16_t> : default_datum_conversion<int16_t> {
220 static int16_t from_datum(const datum &d, oid, std::optional<memory_context>) {
221 return static_cast<int16_t>(d.operator const ::Datum &());
222 }
223 static datum into_datum(const int16_t &t) { return datum(static_cast<::Datum>(t)); }
224};
225
226template <> struct datum_conversion<bool> : default_datum_conversion<bool> {
227 static bool from_datum(const datum &d, oid, std::optional<memory_context>) {
228 return static_cast<bool>(d.operator const ::Datum &());
229 }
230 static datum into_datum(const bool &t) { return datum(static_cast<::Datum>(t)); }
231};
232
233template <> struct datum_conversion<double> : default_datum_conversion<double> {
234 static double from_datum(const datum &d, oid, std::optional<memory_context>) {
235 return DatumGetFloat8(d.operator const ::Datum &());
236 }
237
238 static datum into_datum(const double &t) { return datum(Float8GetDatum(t)); }
239};
240
241template <> struct datum_conversion<float> : default_datum_conversion<float> {
242 static float from_datum(const datum &d, oid, std::optional<memory_context>) {
243 return DatumGetFloat4(d.operator const ::Datum &());
244 }
245
246 static datum into_datum(const float &t) { return datum(Float4GetDatum(t)); }
247};
248
249// Specializations for text and bytea:
250template <> struct datum_conversion<text> : default_datum_conversion<text> {
251 static text from_datum(const datum &d, oid, std::optional<memory_context> ctx) {
252 return text{d, ctx};
253 }
254
255 static datum into_datum(const text &t) { return t.get_datum(); }
256};
257
258template <> struct datum_conversion<bytea> : default_datum_conversion<bytea> {
259 static bytea from_datum(const datum &d, oid, std::optional<memory_context> ctx) {
260 return bytea{d, ctx};
261 }
262
263 static datum into_datum(const bytea &t) { return t.get_datum(); }
264};
265
266template <> struct datum_conversion<byte_array> : default_datum_conversion<byte_array> {
267 static byte_array from_datum(const datum &d, oid, std::optional<memory_context> ctx) {
268 return bytea{d, ctx};
269 }
270
271 static datum into_datum(const byte_array &t) {
272 // This is not perfect if the data was already allocated with Postgres
273 // But once we're with the byte_array (std::span) we've lost this information
274 // TODO: can we do any better here?
275 return bytea(t, memory_context()).get_datum();
276 }
277};
278
279// Specializations for std::string_view and std::string.
280// Here we re-use the conversion for text.
281template <> struct datum_conversion<std::string_view> : default_datum_conversion<std::string_view> {
282 static std::string_view from_datum(const datum &d, oid oid, std::optional<memory_context> ctx) {
284 }
285
286 static datum into_datum(const std::string_view &t) {
287 size_t sz = t.size();
288 void *result = ffi_guard{::palloc}(sz + VARHDRSZ);
289 SET_VARSIZE(result, t.size() + VARHDRSZ);
290 memcpy(VARDATA(result), t.data(), sz);
291 return datum(reinterpret_cast<::Datum>(result));
292 }
293};
294
295template <> struct datum_conversion<std::string> : default_datum_conversion<std::string> {
296 static std::string from_datum(const datum &d, oid oid, std::optional<memory_context> ctx) {
297 // Convert the text to a std::string_view then construct a std::string.
298 return std::string(datum_conversion<text>::from_datum(d, oid, ctx).operator std::string_view());
299 }
300
301 static datum into_datum(const std::string &t) {
303 }
304};
305
307 static const char *from_datum(const datum &d, oid, std::optional<memory_context> ctx) {
308 return DatumGetPointer(d);
309 }
310
311 static datum into_datum(const char *const &t) { return datum(PointerGetDatum(t)); }
312};
313
314template <std::size_t N>
315struct datum_conversion<char[N]> : default_datum_conversion<char[N], const char *> {
316 static const char *from_datum(const datum &d, oid, std::optional<memory_context> ctx) {
317 return DatumGetPointer(d);
318 }
319
320 static datum into_datum(const char (&t)[N]) { return datum(PointerGetDatum(t)); }
321};
322
323template <typename T>
324struct datum_conversion<T, std::enable_if_t<expanded_varlena_type<T>>>
326 static T from_datum(const datum &d, oid, std::optional<memory_context> ctx) { return {d, ctx}; }
327
328 static datum into_datum(const T &t) { return t.get_expanded_datum(); }
329};
330
331template <typename T> struct datum_conversion<T, std::enable_if_t<utils::is_optional<T>>> {
332
333 static T from_nullable_datum(const nullable_datum &d, const oid oid,
334 std::optional<memory_context> context = std::nullopt) {
335 if (d.is_null()) {
336 return std::nullopt;
337 }
338 return from_datum(d, oid, context);
339 }
340
341 static T from_datum(const datum &d, oid oid, std::optional<memory_context> ctx) {
343 }
344
345 static datum into_datum(const T &t) { return t.get_expanded_datum(); }
346};
347
354struct named_type : public type {
360 named_type(const std::string_view name) : type(type{.oid = ::TypenameGetTypid(name.data())}) {}
367 named_type(const std::string_view schema, const std::string_view name)
368 : type({.oid = ([&]() {
369 cppgres::oid nsoid = ffi_guard{::LookupExplicitNamespace}(schema.data(), false);
370 cppgres::oid oid = InvalidOid;
371 if (OidIsValid(nsoid)) {
373 TYPENAMENSP, std::string(name).c_str(), nsoid))
374 .oid;
375 }
376 return oid;
377 })()}) {}
378};
379
380} // namespace cppgres
Definition: type.hpp:128
A trait to convert from and into a cppgres::datum.
Definition: datum.hpp:110
static T from_datum(const datum &, const oid, std::optional< memory_context > context=std::nullopt)=delete
Convert from a datum.
static T from_nullable_datum(const nullable_datum &d, const oid oid, std::optional< memory_context > context=std::nullopt)=delete
Convert from a nullable datum.
static datum into_datum(const T &d)=delete
Convert datum into a type.
Definition: datum.hpp:35
Definition: datum.hpp:137
Definition: type.hpp:155
Definition: guard.hpp:19
Definition: memory.hpp:61
Definition: name.hpp:7
Type identified by its name.
Definition: types.hpp:354
named_type(const std::string_view schema, const std::string_view name)
Type identified by a qualified name.
Definition: types.hpp:367
named_type(const std::string_view name)
Type identified by an unqualified name.
Definition: types.hpp:360
Definition: datum.hpp:56
Definition: datum.hpp:17
Definition: syscache.hpp:27
Definition: type.hpp:118
Definition: type.hpp:41
Postgres type.
Definition: type.hpp:20