libpqxx
The C++ client library for PostgreSQL
field.hxx
1 /* Definitions for the pqxx::field class.
2  *
3  * pqxx::field refers to a field in a query result.
4  *
5  * DO NOT INCLUDE THIS FILE DIRECTLY; include pqxx/field instead.
6  *
7  * Copyright (c) 2000-2024, Jeroen T. Vermeulen.
8  *
9  * See COPYING for copyright license. If you did not receive a file called
10  * COPYING with this source code, please notify the distributor of this
11  * mistake, or contact the author.
12  */
13 #ifndef PQXX_H_FIELD
14 #define PQXX_H_FIELD
15 
16 #if !defined(PQXX_HEADER_PRE)
17 # error "Include libpqxx headers as <pqxx/header>, not <pqxx/header.hxx>."
18 #endif
19 
20 #include <optional>
21 
22 #include "pqxx/array.hxx"
23 #include "pqxx/composite.hxx"
24 #include "pqxx/result.hxx"
25 #include "pqxx/strconv.hxx"
26 #include "pqxx/types.hxx"
27 
28 namespace pqxx
29 {
31 
34 class PQXX_LIBEXPORT field
35 {
36 public:
37  using size_type = field_size_type;
38 
44 
60  [[nodiscard]] PQXX_PURE bool operator==(field const &) const noexcept;
61 
63 
65  [[nodiscard]] PQXX_PURE bool operator!=(field const &rhs) const noexcept
66  {
67  return not operator==(rhs);
68  }
70 
76  [[nodiscard]] PQXX_PURE char const *name() const &;
77 
79  [[nodiscard]] oid PQXX_PURE type() const;
80 
82  [[nodiscard]] PQXX_PURE oid table() const;
83 
85  PQXX_PURE constexpr row_size_type num() const noexcept { return col(); }
86 
88  [[nodiscard]] PQXX_PURE row_size_type table_column() const;
90 
107 
111  [[nodiscard]] PQXX_PURE std::string_view view() const &
112  {
113  return std::string_view(c_str(), size());
114  }
115 
117 
126  [[nodiscard]] PQXX_PURE char const *c_str() const &;
127 
129  [[nodiscard]] PQXX_PURE bool is_null() const noexcept;
130 
132  [[nodiscard]] PQXX_PURE size_type size() const noexcept;
133 
135 
138  template<typename T>
139  auto to(T &obj) const ->
140  typename std::enable_if_t<
141  (not std::is_pointer<T>::value or std::is_same<T, char const *>::value),
142  bool>
143  {
144  if (is_null())
145  {
146  return false;
147  }
148  else
149  {
150  auto const data{c_str()};
151  from_string(data, obj);
152  return true;
153  }
154  }
155 
157 
162  template<typename... T> bool composite_to(T &...fields) const
163  {
164  if (is_null())
165  {
166  return false;
167  }
168  else
169  {
170  parse_composite(m_home.m_encoding, view(), fields...);
171  return true;
172  }
173  }
174 
176  template<typename T> bool operator>>(T &obj) const { return to(obj); }
177 
179 
189  template<typename T>
190  auto to(T &obj, T const &default_value) const ->
191  typename std::enable_if_t<
192  (not std::is_pointer<T>::value or std::is_same<T, char const *>::value),
193  bool>
194  {
195  bool const null{is_null()};
196  if (null)
197  obj = default_value;
198  else
199  obj = from_string<T>(this->view());
200  return not null;
201  }
202 
204 
207  template<typename T> T as(T const &default_value) const
208  {
209  if (is_null())
210  return default_value;
211  else
212  return from_string<T>(this->view());
213  }
214 
216 
221  template<typename T> T as() const
222  {
223  if (is_null())
224  {
225  if constexpr (not nullness<T>::has_null)
226  internal::throw_null_conversion(type_name<T>);
227  else
228  return nullness<T>::null();
229  }
230  else
231  {
232  return from_string<T>(this->view());
233  }
234  }
235 
237 
240  template<typename T, template<typename> class O = std::optional>
241  constexpr O<T> get() const
242  {
243  return as<O<T>>();
244  }
245 
247 
253  array_parser as_array() const & noexcept
254  {
255  return array_parser{c_str(), m_home.m_encoding};
256  }
258 
260 
264  [[deprecated(
265  "Do not construct fields yourself. Get them from the row.")]] field(row const &r, row_size_type c) noexcept;
266 
268  [[deprecated(
269  "Do not construct fields yourself. Get them from the "
270  "row.")]] field() noexcept = default;
271 
272 
273 protected:
274  constexpr result const &home() const noexcept { return m_home; }
275  constexpr result::size_type idx() const noexcept { return m_row; }
276  constexpr row_size_type col() const noexcept { return m_col; }
277 
278  // TODO: Create gates.
279  friend class pqxx::result;
280  friend class pqxx::row;
281  field(
282  result const &r, result_size_type row_num, row_size_type col_num) noexcept
283  :
284  m_col{col_num}, m_home{r}, m_row{row_num}
285  {}
286 
292 
293 private:
294  result m_home;
295  result::size_type m_row;
296 };
297 
298 
299 template<> inline bool field::to<std::string>(std::string &obj) const
300 {
301  bool const null{is_null()};
302  if (not null)
303  obj = std::string{view()};
304  return not null;
305 }
306 
307 
308 template<>
309 inline bool field::to<std::string>(
310  std::string &obj, std::string const &default_value) const
311 {
312  bool const null{is_null()};
313  if (null)
314  obj = default_value;
315  else
316  obj = std::string{view()};
317  return not null;
318 }
319 
320 
322 
327 template<> inline bool field::to<char const *>(char const *&obj) const
328 {
329  bool const null{is_null()};
330  if (not null)
331  obj = c_str();
332  return not null;
333 }
334 
335 
336 template<> inline bool field::to<std::string_view>(std::string_view &obj) const
337 {
338  bool const null{is_null()};
339  if (not null)
340  obj = view();
341  return not null;
342 }
343 
344 
345 template<>
346 inline bool field::to<std::string_view>(
347  std::string_view &obj, std::string_view const &default_value) const
348 {
349  bool const null{is_null()};
350  if (null)
351  obj = default_value;
352  else
353  obj = view();
354  return not null;
355 }
356 
357 
358 template<> inline std::string_view field::as<std::string_view>() const
359 {
360  if (is_null())
361  PQXX_UNLIKELY
362  internal::throw_null_conversion(type_name<std::string_view>);
363  return view();
364 }
365 
366 
367 template<>
368 inline std::string_view
369 field::as<std::string_view>(std::string_view const &default_value) const
370 {
371  return is_null() ? default_value : view();
372 }
373 
374 
375 template<> inline bool field::to<zview>(zview &obj) const
376 {
377  bool const null{is_null()};
378  if (not null)
379  obj = zview{c_str(), size()};
380  return not null;
381 }
382 
383 
384 template<>
385 inline bool field::to<zview>(zview &obj, zview const &default_value) const
386 {
387  bool const null{is_null()};
388  if (null)
389  obj = default_value;
390  else
391  obj = zview{c_str(), size()};
392  return not null;
393 }
394 
395 
396 template<> inline zview field::as<zview>() const
397 {
398  if (is_null())
399  PQXX_UNLIKELY
400  internal::throw_null_conversion(type_name<zview>);
401  return zview{c_str(), size()};
402 }
403 
404 
405 template<> inline zview field::as<zview>(zview const &default_value) const
406 {
407  return is_null() ? default_value : zview{c_str(), size()};
408 }
409 
410 
411 template<typename CHAR = char, typename TRAITS = std::char_traits<CHAR>>
412 class field_streambuf : public std::basic_streambuf<CHAR, TRAITS>
413 {
414 public:
415  using char_type = CHAR;
416  using traits_type = TRAITS;
417  using int_type = typename traits_type::int_type;
418  using pos_type = typename traits_type::pos_type;
419  using off_type = typename traits_type::off_type;
420  using openmode = std::ios::openmode;
421  using seekdir = std::ios::seekdir;
422 
423  explicit field_streambuf(field const &f) : m_field{f} { initialize(); }
424 
425 protected:
426  virtual int sync() override { return traits_type::eof(); }
427 
428  virtual pos_type seekoff(off_type, seekdir, openmode) override
429  {
430  return traits_type::eof();
431  }
432  virtual pos_type seekpos(pos_type, openmode) override
433  {
434  return traits_type::eof();
435  }
436  virtual int_type overflow(int_type) override { return traits_type::eof(); }
437  virtual int_type underflow() override { return traits_type::eof(); }
438 
439 private:
440  field const &m_field;
441 
442  int_type initialize()
443  {
444  auto g{static_cast<char_type *>(const_cast<char *>(m_field.c_str()))};
445  this->setg(g, g, g + std::size(m_field));
446  return int_type(std::size(m_field));
447  }
448 };
449 
450 
452 
465 template<typename CHAR = char, typename TRAITS = std::char_traits<CHAR>>
466 class basic_fieldstream : public std::basic_istream<CHAR, TRAITS>
467 {
468  using super = std::basic_istream<CHAR, TRAITS>;
469 
470 public:
471  using char_type = CHAR;
472  using traits_type = TRAITS;
473  using int_type = typename traits_type::int_type;
474  using pos_type = typename traits_type::pos_type;
475  using off_type = typename traits_type::off_type;
476 
477  [[deprecated("Use field::as<...>() or field::c_str().")]] basic_fieldstream(
478  field const &f) :
479  super{nullptr}, m_buf{f}
480  {
481  super::init(&m_buf);
482  }
483 
484 private:
486 };
487 
488 
491 
492 
494 
517 template<typename CHAR>
518 [[deprecated(
519  "Do this by hand, probably with better error checking.")]] inline std::
520  basic_ostream<CHAR> &
521  operator<<(std::basic_ostream<CHAR> &s, field const &value)
522 {
523  s.write(value.c_str(), std::streamsize(std::size(value)));
524  return s;
525 }
526 
527 
529 
532 template<typename T> inline T from_string(field const &value)
533 {
534  if (value.is_null())
535  {
536  if constexpr (nullness<T>::has_null)
537  return nullness<T>::null();
538  else
539  internal::throw_null_conversion(type_name<T>);
540  }
541  else
542  {
543  return from_string<T>(value.view());
544  }
545 }
546 
547 
549 
555 template<>
556 inline std::nullptr_t from_string<std::nullptr_t>(field const &value)
557 {
558  if (not value.is_null())
559  throw conversion_error{
560  "Extracting non-null field into nullptr_t variable."};
561  return nullptr;
562 }
563 
564 
566 template<> PQXX_LIBEXPORT std::string to_string(field const &value);
567 } // namespace pqxx
568 #endif
Low-level array parser.
Definition: array.hxx:529
Input stream that gets its data from a result field.
Definition: field.hxx:467
Definition: field.hxx:413
Reference to a field in a result set.
Definition: field.hxx:35
PQXX_PURE size_type size() const noexcept
Return number of bytes taken up by the field's value.
Definition: field.cxx:77
T as(T const &default_value) const
Return value as object of given type, or default value if null.
Definition: field.hxx:207
row_size_type m_col
Definition: field.hxx:291
array_parser as_array() const &noexcept
Parse the field as an SQL array.
Definition: field.hxx:253
auto to(T &obj, T const &default_value) const -> typename std::enable_if_t<(not std::is_pointer< T >::value or std::is_same< T, char const * >::value), bool >
Read value into obj; or if null, use default value and return false.
Definition: field.hxx:190
constexpr O< T > get() const
Return value wrapped in some optional type (empty for nulls).
Definition: field.hxx:241
bool operator>>(T &obj) const
Read value into obj; or leave obj untouched and return false if null.
Definition: field.hxx:176
PQXX_PURE bool operator!=(field const &rhs) const noexcept
Byte-by-byte comparison (all nulls are considered equal)
Definition: field.hxx:65
PQXX_PURE char const * c_str() const &
Read as plain C string.
Definition: field.cxx:65
T as() const
Return value as object of given type, or throw exception if null.
Definition: field.hxx:221
PQXX_PURE std::string_view view() const &
Read as string_view, or an empty one if null.
Definition: field.hxx:111
bool composite_to(T &...fields) const
Read field as a composite value, write its components into fields.
Definition: field.hxx:162
field() noexcept=default
Constructor. Do not call this yourself; libpqxx will do it for you.
PQXX_PURE bool is_null() const noexcept
Is this field's value null?
Definition: field.cxx:71
Result set containing data returned by a query or command.
Definition: result.hxx:73
Reference to one row in a result.
Definition: row.hxx:47
Marker-type wrapper: zero-terminated std::string_view.
Definition: zview.hxx:38
Value conversion failed, e.g. when converting "Hello" to int.
Definition: except.hxx:283
void throw_null_conversion(std::string const &type)
Throw exception for attempt to convert SQL NULL to given type.
Definition: strconv.cxx:255
The home of all libpqxx classes, functions, templates, etc.
Definition: array.cxx:27
int row_size_type
Number of fields in a row of database data.
Definition: types.hxx:34
std::size_t field_size_type
Number of bytes in a field of database data.
Definition: types.hxx:40
int result_size_type
Number of rows in a result set.
Definition: types.hxx:28
constexpr bool is_null(TYPE const &value) noexcept
Is value null?
Definition: strconv.hxx:514
std::basic_ostream< CHAR > & operator<<(std::basic_ostream< CHAR > &s, field const &value)
Write a result field to any type of stream.
Definition: field.hxx:521
void parse_composite(pqxx::internal::encoding_group enc, std::string_view text, T &...fields)
Parse a string representation of a value of a composite type.
Definition: composite.hxx:35
unsigned int oid
PostgreSQL database row identifier.
Definition: libpq-forward.hxx:33
PQXX_LIBEXPORT std::string to_string(field const &value)
Convert a field to a string.
Definition: result.cxx:566
T from_string(field const &value)
Convert a field's value to type T.
Definition: field.hxx:532
Traits describing a type's "null value," if any.
Definition: strconv.hxx:91
static TYPE null()
Return a null value.