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