6#include <initializer_list>
15#include <fmt/format.h>
17#include <userver/storages/postgres/exceptions.hpp>
18#include <userver/storages/postgres/io/supported_types.hpp>
19#include <userver/storages/postgres/postgres_fwd.hpp>
21#include <userver/storages/postgres/detail/const_data_iterator.hpp>
23#include <userver/compiler/demangle.hpp>
24#include <userver/logging/log.hpp>
26USERVER_NAMESPACE_BEGIN
212 RowDescription(detail::ResultWrapperPtr res) : res_{std::move(res)} {}
219 detail::ResultWrapperPtr res_;
224template <
typename T,
typename ExtractionTag>
230 using size_type = std::size_t;
232 size_type RowIndex()
const {
return row_index_; }
233 size_type FieldIndex()
const {
return field_index_; }
241 Oid GetTypeOid()
const;
251 template <
typename T>
252 size_type
To(T&& val)
const {
253 using ValueType =
typename std::decay<T>::type;
254 auto fb = GetBuffer();
255 return ReadNullable(fb, std::forward<T>(val),
261 template <
typename T>
262 void Coalesce(T& val,
const T& default_val)
const {
272 template <
typename T>
273 typename std::decay<T>::
type As()
const {
281 template <
typename T>
283 if (IsNull())
return default_val;
287 const io::TypeBufferCategory& GetTypeBufferCategories()
const;
295 Field(detail::ResultWrapperPtr res, size_type row, size_type col)
296 : res_{std::move(res)}, row_index_{row}, field_index_{col} {}
298 template <
typename T>
300 std::true_type)
const {
301 using ValueType =
typename std::decay<T>::type;
304 NullSetter::SetNull(val);
306 Read(fb, std::forward<T>(val));
310 template <
typename T>
311 size_type ReadNullable(
const io::
FieldBuffer& buffer, T&& val,
312 std::false_type)
const {
313 if (buffer.is_null) {
314 throw FieldValueIsNull{field_index_, Name(), val};
316 Read(buffer, std::forward<T>(val));
318 return buffer.length;
323 bool IsValid()
const;
324 int Compare(
const Field& rhs)
const;
325 std::ptrdiff_t Distance(
const Field& rhs)
const;
326 Field& Advance(std::ptrdiff_t);
330 template <
typename T>
332 using ValueType =
typename std::decay<T>::type;
333 io::
traits::CheckParser<ValueType>();
335 io::ReadBuffer(buffer, std::forward<T>(val), GetTypeBufferCategories());
337 ex.AddMsgSuffix(fmt::format(
338 " (field #{} name `{}` C++ type `{}`. Postgres ResultSet error)",
339 field_index_, Name(), compiler::GetTypeName<T>()));
344 detail::ResultWrapperPtr res_;
345 size_type row_index_;
346 size_type field_index_;
355 ConstFieldIterator(detail::ResultWrapperPtr res, size_type row, size_type col)
356 : ConstDataIterator(std::move(res), row, col) {}
365 ReverseConstFieldIterator(detail::ResultWrapperPtr res, size_type row,
367 : ConstDataIterator(std::move(res), row, col) {}
379 using size_type = std::size_t;
383 using value_type =
Field;
384 using reference =
Field;
385 using pointer = const_iterator;
388 size_type RowIndex()
const {
return row_index_; }
398 const_iterator cbegin()
const;
399 const_iterator begin()
const {
return cbegin(); }
400 const_iterator cend()
const;
401 const_iterator end()
const {
return cend(); }
405 const_reverse_iterator crbegin()
const;
406 const_reverse_iterator rbegin()
const {
return crbegin(); }
407 const_reverse_iterator crend()
const;
408 const_reverse_iterator rend()
const {
return crend(); }
417 reference
operator[](
const std::string& name)
const;
440 template <
typename T>
441 void To(T&& val)
const;
445 template <
typename T>
453 template <
typename T>
457 template <
typename... T>
458 void To(T&&... val)
const;
470 template <
typename T,
typename... Y>
477 template <
typename T>
488 template <
typename T>
496 template <
typename... T>
497 void To(
const std::initializer_list<std::string>& names, T&&... val)
const;
498 template <
typename... T>
499 std::tuple<T...> As(
const std::initializer_list<std::string>& names)
const;
503 template <
typename... T>
504 void To(
const std::initializer_list<size_type>& indexes, T&&... val)
const;
505 template <
typename... T>
506 std::tuple<T...> As(
const std::initializer_list<size_type>& indexes)
const;
509 size_type IndexOfName(
const std::string&)
const;
514 Row(detail::ResultWrapperPtr res, size_type row)
515 : res_{std::move(res)}, row_index_{row} {}
519 bool IsValid()
const;
520 int Compare(
const Row& rhs)
const;
521 std::ptrdiff_t Distance(
const Row& rhs)
const;
522 Row& Advance(std::ptrdiff_t);
525 detail::ResultWrapperPtr res_;
526 size_type row_index_;
535 ConstRowIterator(detail::ResultWrapperPtr res, size_type row)
536 : ConstDataIterator(std::move(res), row) {}
545 ReverseConstRowIterator(detail::ResultWrapperPtr res, size_type row)
546 : ConstDataIterator(std::move(res), row) {}
564 using size_type = std::size_t;
565 using difference_type = std::ptrdiff_t;
566 static constexpr size_type npos = std::numeric_limits<size_type>::max();
573 using value_type =
Row;
574 using reference = value_type;
575 using pointer = const_iterator;
578 explicit ResultSet(std::shared_ptr<detail::ResultWrapper> pimpl)
579 : pimpl_{std::move(pimpl)} {}
583 bool IsEmpty()
const {
return Size() == 0; }
585 size_type RowsAffected()
const;
586 std::string CommandStatus()
const;
592 const_iterator cbegin()
const&;
593 const_iterator begin()
const& {
return cbegin(); }
594 const_iterator cend()
const&;
595 const_iterator end()
const& {
return cend(); }
598 const_iterator cbegin()
const&& =
delete;
599 const_iterator begin()
const&& =
delete;
600 const_iterator cend()
const&& =
delete;
601 const_iterator end()
const&& =
delete;
605 const_reverse_iterator crbegin()
const&;
606 const_reverse_iterator rbegin()
const& {
return crbegin(); }
607 const_reverse_iterator crend()
const&;
608 const_reverse_iterator rend()
const& {
return crend(); }
610 const_reverse_iterator crbegin()
const&& =
delete;
611 const_reverse_iterator rbegin()
const&& =
delete;
612 const_reverse_iterator crend()
const&& =
delete;
613 const_reverse_iterator rend()
const&& =
delete;
616 reference Front()
const&;
617 reference Back()
const&;
619 reference Front()
const&& =
delete;
620 reference Back()
const&& =
delete;
626 reference operator[](size_type index)
const&& =
delete;
632 size_type FieldCount()
const;
642 template <
typename T>
644 template <
typename T>
645 auto AsSetOf(
RowTag)
const;
646 template <
typename T>
651 template <
typename Container>
653 template <
typename Container>
654 Container AsContainer(
RowTag)
const;
659 template <
typename T>
661 template <
typename T>
662 auto AsSingleRow(
RowTag)
const;
663 template <
typename T>
667 friend class detail::ConnectionImpl;
668 void FillBufferCategories(
const UserTypes& types);
669 void SetBufferCategoriesFrom(
const ResultSet&);
671 template <
typename T,
typename Tag>
672 friend class TypedResultSet;
673 friend class ConnectionImpl;
675 std::shared_ptr<detail::ResultWrapper> pimpl_;
681struct IsOptionalFromOptional : std::false_type {};
684struct IsOptionalFromOptional<std::optional<std::optional<T>>>
688struct IsOneVariant : std::false_type {};
691struct IsOneVariant<std::variant<T>> : std::true_type {};
693template <
typename... Args>
694constexpr void AssertSaneTypeToDeserialize() {
696 !(IsOptionalFromOptional<
697 std::remove_const_t<std::remove_reference_t<Args>>>::value ||
699 "Attempt to get an optional<optional<T>> was detected. Such "
700 "optional-from-optional types are very error prone, obfuscate code and "
701 "are ambiguous to deserialize. Change the type to just optional<T>");
704 std::remove_const_t<std::remove_reference_t<Args>>>::value ||
706 "Attempt to get an variant<T> was detected. Such variant from one type "
707 "obfuscates code. Change the type to just T");
712template <
typename IndexTuple,
typename... T>
713struct RowDataExtractorBase;
715template <std::size_t... Indexes,
typename... T>
716struct RowDataExtractorBase<std::index_sequence<Indexes...>, T...> {
717 static void ExtractValues(
const Row& row, T&&... val) {
718 static_assert(
sizeof...(Indexes) ==
sizeof...(T));
722 auto it = row.begin();
723 const auto perform = [&](
auto&& arg) {
724 it->To(std::forward<
decltype(arg)>(arg));
727 (perform(std::forward<T>(val)), ...);
729 static void ExtractTuple(
const Row& row, std::tuple<T...>& val) {
730 static_assert(
sizeof...(Indexes) ==
sizeof...(T));
734 auto it = row.begin();
735 const auto perform = [&](
auto& arg) {
739 (perform(std::get<Indexes>(val)), ...);
741 static void ExtractTuple(
const Row& row, std::tuple<T...>&& val) {
742 static_assert(
sizeof...(Indexes) ==
sizeof...(T));
746 auto it = row.begin();
747 const auto perform = [&](
auto& arg) {
751 (perform(std::get<Indexes>(val)), ...);
754 static void ExtractValues(
const Row& row,
755 const std::initializer_list<std::string>& names,
757 (row[*(names.begin() + Indexes)].To(std::forward<T>(val)), ...);
759 static void ExtractTuple(
const Row& row,
760 const std::initializer_list<std::string>& names,
761 std::tuple<T...>& val) {
762 std::tuple<T...> tmp{row[*(names.begin() + Indexes)].
template As<T>()...};
766 static void ExtractValues(
const Row& row,
767 const std::initializer_list<std::size_t>& indexes,
769 (row[*(indexes.begin() + Indexes)].To(std::forward<T>(val)), ...);
771 static void ExtractTuple(
const Row& row,
772 const std::initializer_list<std::size_t>& indexes,
773 std::tuple<T...>& val) {
774 std::tuple<T...> tmp{row[*(indexes.begin() + Indexes)].
template As<T>()...};
779template <
typename... T>
780struct RowDataExtractor
781 : RowDataExtractorBase<std::index_sequence_for<T...>, T...> {};
784struct TupleDataExtractor;
785template <
typename... T>
786struct TupleDataExtractor<std::tuple<T...>>
787 : RowDataExtractorBase<std::index_sequence_for<T...>, T...> {};
794 To(std::forward<T>(val), kFieldTag);
799 detail::AssertSaneTypeToDeserialize<T>();
801 using ValueType = std::decay_t<T>;
802 static_assert(io::traits::kIsRowType<ValueType>,
803 "This type cannot be used as a row type");
804 using RowType = io::RowType<ValueType>;
805 using TupleType =
typename RowType::TupleType;
806 constexpr auto tuple_size = RowType::size;
807 if (tuple_size > Size()) {
808 throw InvalidTupleSizeRequested(Size(), tuple_size);
809 }
else if (tuple_size < Size()) {
811 <<
"Row size is greater that the number of data members in "
816 detail::TupleDataExtractor<TupleType>::ExtractTuple(
817 *
this, RowType::GetTuple(std::forward<T>(val)));
822 detail::AssertSaneTypeToDeserialize<T>();
823 using ValueType = std::decay_t<T>;
825 static_assert(io::traits::kIsMappedToPg<ValueType> ||
826 io::traits::kIsCompositeType<ValueType>,
827 "This type is not mapped to a PostgreSQL type");
835 (*
this)
[0
].To(std::forward<T>(val));
838template <
typename... T>
840 detail::AssertSaneTypeToDeserialize<T...>();
841 if (
sizeof...(T) >
Size()) {
844 detail::RowDataExtractor<T...>::ExtractValues(*
this, std::forward<T>(val)...);
847template <
typename T,
typename... Y>
849 if constexpr (
sizeof...(Y) > 0) {
850 std::tuple<T, Y...> res;
854 return As<T>(kFieldTag);
858template <
typename... T>
859void Row::
To(
const std::initializer_list<std::string>& names,
861 detail::AssertSaneTypeToDeserialize<T...>();
862 if (
sizeof...(T) != names.size()) {
863 throw FieldTupleMismatch(names.size(),
sizeof...(T));
865 detail::RowDataExtractor<T...>::ExtractValues(*
this, names,
866 std::forward<T>(val)...);
869template <
typename... T>
870std::tuple<T...>
Row::As(
871 const std::initializer_list<std::string>& names)
const {
872 if (
sizeof...(T) != names.size()) {
873 throw FieldTupleMismatch(names.size(),
sizeof...(T));
875 std::tuple<T...> res;
876 detail::RowDataExtractor<T...>::ExtractTuple(*
this, names, res);
880template <
typename... T>
881void Row::
To(
const std::initializer_list<size_type>& indexes,
883 detail::AssertSaneTypeToDeserialize<T...>();
884 if (
sizeof...(T) != indexes.size()) {
885 throw FieldTupleMismatch(indexes.size(),
sizeof...(T));
887 detail::RowDataExtractor<T...>::ExtractValues(*
this, indexes,
888 std::forward<T>(val)...);
891template <
typename... T>
892std::tuple<T...>
Row::As(
893 const std::initializer_list<size_type>& indexes)
const {
894 if (
sizeof...(T) != indexes.size()) {
895 throw FieldTupleMismatch(indexes.size(),
sizeof...(T));
897 std::tuple<T...> res;
898 detail::RowDataExtractor<T...>::ExtractTuple(*
this, indexes, res);
904 return AsSetOf<T>(kFieldTag);
909 detail::AssertSaneTypeToDeserialize<T>();
910 using ValueType = std::decay_t<T>;
911 static_assert(io::traits::kIsRowType<ValueType>,
912 "This type cannot be used as a row type");
913 return TypedResultSet<T,
RowTag>{*
this};
918 detail::AssertSaneTypeToDeserialize<T>();
919 using ValueType = std::decay_t<T>;
921 static_assert(io::traits::kIsMappedToPg<ValueType> ||
922 io::traits::kIsCompositeType<ValueType>,
923 "This type is not mapped to a PostgreSQL type");
924 if (FieldCount() > 1) {
928 return TypedResultSet<T,
FieldTag>{*
this};
931template <
typename Container>
933 detail::AssertSaneTypeToDeserialize<Container>();
934 using ValueType =
typename Container::value_type;
936 if constexpr (
io::
traits::kCanReserve<Container>) {
939 auto res = AsSetOf<ValueType>();
940 std::copy(res.begin(), res.end(),
io::
traits::Inserter(c));
944template <
typename Container>
946 detail::AssertSaneTypeToDeserialize<Container>();
947 using ValueType =
typename Container::value_type;
949 if constexpr (
io::
traits::kCanReserve<Container>) {
952 auto res = AsSetOf<ValueType>(kRowTag);
953 std::copy(res.begin(), res.end(),
io::
traits::Inserter(c));
959 return AsSingleRow<T>(kFieldTag);
964 detail::AssertSaneTypeToDeserialize<T>();
968 return Front().As<T>(kRowTag);
973 detail::AssertSaneTypeToDeserialize<T>();
977 return Front().As<T>(kFieldTag);
984#include <userver/storages/postgres/typed_result_set.hpp>