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