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-2025, 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 
43 
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 
75  [[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 
106 
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  template<typename ELEMENT, auto... ARGS>
248  array<ELEMENT, ARGS...> as_sql_array() const
249  {
250  using array_type = array<ELEMENT, ARGS...>;
251 
252  // There's no such thing as a null SQL array.
253  if (is_null())
254  internal::throw_null_conversion(type_name<array_type>);
255  else
256  return array_type{this->view(), this->m_home.m_encoding};
257  }
258 
260 
266  [[deprecated(
267  "Avoid pqxx::array_parser. "
268  "Instead, use as_sql_array() to convert to pqxx::array.")]]
269  array_parser as_array() const & noexcept
270  {
271  return array_parser{c_str(), m_home.m_encoding};
272  }
274 
276 
280  [[deprecated(
281  "Do not construct fields yourself. Get them from the row.")]] field(row const &r, row_size_type c) noexcept;
282 
284  [[deprecated(
285  "Do not construct fields yourself. Get them from the "
286  "row.")]] field() noexcept = default;
287 
288 
289 protected:
290  constexpr result const &home() const noexcept { return m_home; }
291  constexpr result::size_type idx() const noexcept { return m_row; }
292  constexpr row_size_type col() const noexcept { return m_col; }
293 
294  // TODO: Create gates.
295  friend class pqxx::result;
296  friend class pqxx::row;
297  field(
298  result const &r, result_size_type row_num, row_size_type col_num) noexcept
299  :
300  m_col{col_num}, m_home{r}, m_row{row_num}
301  {}
302 
308 
309 private:
310  result m_home;
311  result::size_type m_row;
312 };
313 
314 
315 template<> inline bool field::to<std::string>(std::string &obj) const
316 {
317  bool const null{is_null()};
318  if (not null)
319  obj = std::string{view()};
320  return not null;
321 }
322 
323 
324 template<>
325 inline bool field::to<std::string>(
326  std::string &obj, std::string const &default_value) const
327 {
328  bool const null{is_null()};
329  if (null)
330  obj = default_value;
331  else
332  obj = std::string{view()};
333  return not null;
334 }
335 
336 
338 
343 template<> inline bool field::to<char const *>(char const *&obj) const
344 {
345  bool const null{is_null()};
346  if (not null)
347  obj = c_str();
348  return not null;
349 }
350 
351 
352 template<> inline bool field::to<std::string_view>(std::string_view &obj) const
353 {
354  bool const null{is_null()};
355  if (not null)
356  obj = view();
357  return not null;
358 }
359 
360 
361 template<>
362 inline bool field::to<std::string_view>(
363  std::string_view &obj, std::string_view const &default_value) const
364 {
365  bool const null{is_null()};
366  if (null)
367  obj = default_value;
368  else
369  obj = view();
370  return not null;
371 }
372 
373 
374 template<> inline std::string_view field::as<std::string_view>() const
375 {
376  if (is_null())
377  PQXX_UNLIKELY
378  internal::throw_null_conversion(type_name<std::string_view>);
379  return view();
380 }
381 
382 
383 template<>
384 inline std::string_view
385 field::as<std::string_view>(std::string_view const &default_value) const
386 {
387  return is_null() ? default_value : view();
388 }
389 
390 
391 template<> inline bool field::to<zview>(zview &obj) const
392 {
393  bool const null{is_null()};
394  if (not null)
395  obj = zview{c_str(), size()};
396  return not null;
397 }
398 
399 
400 template<>
401 inline bool field::to<zview>(zview &obj, zview const &default_value) const
402 {
403  bool const null{is_null()};
404  if (null)
405  obj = default_value;
406  else
407  obj = zview{c_str(), size()};
408  return not null;
409 }
410 
411 
412 template<> inline zview field::as<zview>() const
413 {
414  if (is_null())
415  PQXX_UNLIKELY
416  internal::throw_null_conversion(type_name<zview>);
417  return zview{c_str(), size()};
418 }
419 
420 
421 template<> inline zview field::as<zview>(zview const &default_value) const
422 {
423  return is_null() ? default_value : zview{c_str(), size()};
424 }
425 
426 
427 template<typename CHAR = char, typename TRAITS = std::char_traits<CHAR>>
428 class field_streambuf : public std::basic_streambuf<CHAR, TRAITS>
429 {
430 public:
431  using char_type = CHAR;
432  using traits_type = TRAITS;
433  using int_type = typename traits_type::int_type;
434  using pos_type = typename traits_type::pos_type;
435  using off_type = typename traits_type::off_type;
436  using openmode = std::ios::openmode;
437  using seekdir = std::ios::seekdir;
438 
439  explicit field_streambuf(field const &f) : m_field{f} { initialize(); }
440 
441 protected:
442  virtual int sync() override { return traits_type::eof(); }
443 
444  virtual pos_type seekoff(off_type, seekdir, openmode) override
445  {
446  return traits_type::eof();
447  }
448  virtual pos_type seekpos(pos_type, openmode) override
449  {
450  return traits_type::eof();
451  }
452  virtual int_type overflow(int_type) override { return traits_type::eof(); }
453  virtual int_type underflow() override { return traits_type::eof(); }
454 
455 private:
456  field const &m_field;
457 
458  int_type initialize()
459  {
460  auto g{static_cast<char_type *>(const_cast<char *>(m_field.c_str()))};
461  this->setg(g, g, g + std::size(m_field));
462  return int_type(std::size(m_field));
463  }
464 };
465 
466 
468 
481 template<typename CHAR = char, typename TRAITS = std::char_traits<CHAR>>
482 class basic_fieldstream : public std::basic_istream<CHAR, TRAITS>
483 {
484  using super = std::basic_istream<CHAR, TRAITS>;
485 
486 public:
487  using char_type = CHAR;
488  using traits_type = TRAITS;
489  using int_type = typename traits_type::int_type;
490  using pos_type = typename traits_type::pos_type;
491  using off_type = typename traits_type::off_type;
492 
493  [[deprecated("Use field::as<...>() or field::c_str().")]] basic_fieldstream(
494  field const &f) :
495  super{nullptr}, m_buf{f}
496  {
497  super::init(&m_buf);
498  }
499 
500 private:
502 };
503 
504 
507 
508 
510 
533 template<typename CHAR>
534 [[deprecated(
535  "Do this by hand, probably with better error checking.")]] inline std::
536  basic_ostream<CHAR> &
537  operator<<(std::basic_ostream<CHAR> &s, field const &value)
538 {
539  s.write(value.c_str(), std::streamsize(std::size(value)));
540  return s;
541 }
542 
543 
545 
548 template<typename T> inline T from_string(field const &value)
549 {
550  if (value.is_null())
551  {
552  if constexpr (nullness<T>::has_null)
553  return nullness<T>::null();
554  else
555  internal::throw_null_conversion(type_name<T>);
556  }
557  else
558  {
559  return from_string<T>(value.view());
560  }
561 }
562 
563 
565 
571 template<>
572 inline std::nullptr_t from_string<std::nullptr_t>(field const &value)
573 {
574  if (not value.is_null())
575  throw conversion_error{
576  "Extracting non-null field into nullptr_t variable."};
577  return nullptr;
578 }
579 
580 
582 template<> PQXX_LIBEXPORT std::string to_string(field const &value);
583 } // namespace pqxx
584 #endif
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
Definition: field.hxx:428
Low-level parser for C++ arrays.
Definition: array.hxx:530
Reference to one row in a result.
Definition: row.hxx:46
T from_string(field const &value)
Convert a field's value to type T.
Definition: field.hxx:548
int row_size_type
Number of fields in a row of database data.
Definition: types.hxx:34
Result set containing data returned by a query or command.
Definition: result.hxx:91
PQXX_LIBEXPORT std::string to_string(field const &value)
Convert a field to a string.
array_parser as_array() const &noexcept
Parse the field as an SQL array.
Definition: field.hxx:269
bool composite_to(T &...fields) const
Read field as a composite value, write its components into fields.
Definition: field.hxx:162
int result_size_type
Number of rows in a result set.
Definition: types.hxx:28
array< ELEMENT, ARGS... > as_sql_array() const
Read SQL array contents as a pqxx::array.
Definition: field.hxx:248
constexpr bool is_null(TYPE const &value) noexcept
Is value null?
Definition: strconv.hxx:515
PQXX_PURE std::string_view view() const &
Read as string_view, or an empty one if null.
Definition: field.hxx:111
T as(T const &default_value) const
Return value as object of given type, or default value if null.
Definition: field.hxx:207
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
Value conversion failed, e.g. when converting "Hello" to int.
Definition: except.hxx:282
static TYPE null()
Return a null value.
The home of all libpqxx classes, functions, templates, etc.
Definition: array.cxx:26
Reference to a field in a result set.
Definition: field.hxx:34
unsigned int oid
PostgreSQL database row identifier.
Definition: libpq-forward.hxx:33
std::size_t field_size_type
Number of bytes in a field of database data.
Definition: types.hxx:40
Traits describing a type's "null value," if any.
Definition: strconv.hxx:90
void throw_null_conversion(std::string const &type)
Throw exception for attempt to convert SQL NULL to given type.
Definition: strconv.cxx:256
row_size_type m_col
Definition: field.hxx:307
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
T as() const
Return value as object of given type, or throw exception if null.
Definition: field.hxx:221
Input stream that gets its data from a result field.
Definition: field.hxx:482
PQXX_PURE char const * c_str() const &
Read as plain C string.
Definition: field.cxx:65
PQXX_PURE bool is_null() const noexcept
Is this field's value null?
Definition: field.cxx:71
An SQL array received from the database.
Definition: array.hxx:55