5#include <userver/storages/postgres/io/nullable_traits.hpp> 
    6#include <userver/storages/postgres/io/traits.hpp> 
    7#include <userver/storages/postgres/io/type_mapping.hpp> 
    9#include <userver/storages/postgres/io/supported_types.hpp> 
   11#include <userver/storages/postgres/null.hpp> 
   13USERVER_NAMESPACE_BEGIN
 
   18class QueryParameters {
 
   20  QueryParameters() = 
default;
 
   22  template <
class ParamsHolder>
 
   23  explicit QueryParameters(ParamsHolder& ph)
 
   25        types_(ph.ParamTypesBuffer()),
 
   26        values_(ph.ParamBuffers()),
 
   27        lengths_(ph.ParamLengthsBuffer()),
 
   28        formats_(ph.ParamFormatsBuffer()) {}
 
   30  bool Empty() 
const { 
return size_ == 0; }
 
   31  std::size_t Size() 
const { 
return size_; }
 
   32  const char* 
const* ParamBuffers() 
const { 
return values_; }
 
   33  const Oid* ParamTypesBuffer() 
const { 
return types_; }
 
   34  const int* ParamLengthsBuffer() 
const { 
return lengths_; }
 
   35  const int* ParamFormatsBuffer() 
const { 
return formats_; }
 
   37  std::size_t TypeHash() 
const;
 
   40  std::size_t size_ = 0;
 
   41  const Oid* types_ = 
nullptr;
 
   42  const char* 
const* values_ = 
nullptr;
 
   43  const int* lengths_ = 
nullptr;
 
   44  const int* formats_ = 
nullptr;
 
   47template <std::size_t ParamsCount>
 
   48class StaticQueryParameters {
 
   50  StaticQueryParameters() = 
default;
 
   51  StaticQueryParameters(
const StaticQueryParameters&) = 
delete;
 
   52  StaticQueryParameters(StaticQueryParameters&&) = 
delete;
 
   53  StaticQueryParameters& operator=(
const StaticQueryParameters&) = 
delete;
 
   54  StaticQueryParameters& operator=(StaticQueryParameters&&) = 
delete;
 
   56  std::size_t Size() 
const { 
return ParamsCount; }
 
   57  const char* 
const* ParamBuffers() 
const { 
return param_buffers; }
 
   58  const Oid* ParamTypesBuffer() 
const { 
return param_types; }
 
   59  const int* ParamLengthsBuffer() 
const { 
return param_lengths; }
 
   60  const int* ParamFormatsBuffer() 
const { 
return param_formats; }
 
   63  void Write(std::size_t index, 
const UserTypes& types, 
const T& arg) {
 
   64    static_assert(
io::
traits::kIsMappedToPg<T> || std::is_enum_v<T>,
 
   65                  "Type doesn't have mapping to Postgres type.");
 
   67        io::
traits::kIsMappedToPg<T> || !std::is_enum_v<T>,
 
   68        "Type doesn't have mapping to Postgres type. " 
   69        "Enums should be either streamed as their underlying value via the " 
   70        "`template<> struct CanUseEnumAsStrongTypedef<T>: std::true_type {};` " 
   71        "specialization or as a PostgreSQL datatype via the " 
   72        "`template<> struct CppToUserPg<T> : EnumMappingBase<R> { ... };` " 
   74        "See page `uPg: Supported data types` for more information.");
 
   75    WriteParamType(index, types, arg);
 
   79  template <
typename... T>
 
   80  void Write(
const UserTypes& types, 
const T&... args) {
 
   81    std::size_t index = 0;
 
   82    (Write(index++, types, args), ...);
 
   87  void WriteParamType(std::size_t index, 
const UserTypes& types, 
const T&) {
 
   89    param_types[index] = io::CppToPg<T>::GetOid(types);
 
   93  void WriteNullable(std::size_t index, 
const UserTypes& types, 
const T& arg,
 
   96    if (NullDetector::IsNull(arg)) {
 
   97      param_formats[index] = 
io::kPgBinaryDataFormat;
 
   99      param_buffers[index] = 
nullptr;
 
  101      WriteNullable(index, types, arg, std::false_type{});
 
  105  template <
typename T>
 
  106  void WriteNullable(std::size_t index, 
const UserTypes& types, 
const T& arg,
 
  108    param_formats[index] = 
io::kPgBinaryDataFormat;
 
  109    auto& buffer = parameters[index];
 
  110    io::WriteBuffer(types, buffer, arg);
 
  111    auto size = buffer.size();
 
  112    param_lengths[index] = size;
 
  114      param_buffers[index] = empty_buffer;
 
  116      param_buffers[index] = buffer.data();
 
  120  using OidList = Oid[ParamsCount];
 
  121  using BufferType = std::string;
 
  122  using ParameterList = BufferType[ParamsCount];
 
  123  using IntList = 
int[ParamsCount];
 
  125  static constexpr const char* empty_buffer = 
"";
 
  127  ParameterList parameters{};
 
  128  OidList param_types{};
 
  129  const char* param_buffers[ParamsCount]{};
 
  130  IntList param_lengths{};
 
  131  IntList param_formats{};
 
  135class StaticQueryParameters<0> {
 
  137  static std::size_t Size() { 
return 0; }
 
  138  static const char* 
const* ParamBuffers() { 
return nullptr; }
 
  139  static const Oid* ParamTypesBuffer() { 
return nullptr; }
 
  140  static const int* ParamLengthsBuffer() { 
return nullptr; }
 
  141  static const int* ParamFormatsBuffer() { 
return nullptr; }
 
  146class DynamicQueryParameters {
 
  148  DynamicQueryParameters() = 
default;
 
  149  DynamicQueryParameters(
const DynamicQueryParameters&) = 
delete;
 
  150  DynamicQueryParameters(DynamicQueryParameters&&) = 
default;
 
  151  DynamicQueryParameters& operator=(
const DynamicQueryParameters&) = 
delete;
 
  152  DynamicQueryParameters& operator=(DynamicQueryParameters&&) = 
default;
 
  154  std::size_t Size() 
const { 
return param_types.size(); }
 
  155  const char* 
const* ParamBuffers() 
const { 
return param_buffers.data(); }
 
  156  const Oid* ParamTypesBuffer() 
const { 
return param_types.data(); }
 
  157  const int* ParamLengthsBuffer() 
const { 
return param_lengths.data(); }
 
  158  const int* ParamFormatsBuffer() 
const { 
return param_formats.data(); }
 
  160  template <
typename T>
 
  161  void Write(
const UserTypes& types, 
const T& arg) {
 
  162    static_assert(
io::
traits::kIsMappedToPg<T>,
 
  163                  "Type doesn't have mapping to Postgres type");
 
  164    WriteParamType(types, arg);
 
  168  template <
typename... T>
 
  169  void Write(
const UserTypes& types, 
const T&... args) {
 
  170    (Write(types, args), ...);
 
  174  template <
typename T>
 
  175  void WriteParamType(
const UserTypes& types, 
const T&) {
 
  177    param_types.push_back(io::CppToPg<T>::GetOid(types));
 
  180  template <
typename T>
 
  181  void WriteNullable(
const UserTypes& types, 
const T& arg, std::true_type) {
 
  183    if (NullDetector::IsNull(arg)) {
 
  184      param_formats.push_back(io::kPgBinaryDataFormat);
 
  185      param_lengths.push_back(io::kPgNullBufferSize);
 
  186      param_buffers.push_back(
nullptr);
 
  188      WriteNullable(types, arg, std::false_type{});
 
  192  template <
typename T>
 
  193  void WriteNullable(
const UserTypes& types, 
const T& arg, std::false_type) {
 
  194    param_formats.push_back(io::kPgBinaryDataFormat);
 
  195    auto& buffer = parameters.emplace_back();
 
  196    io::WriteBuffer(types, buffer, arg);
 
  197    auto size = buffer.size();
 
  198    param_lengths.push_back(size);
 
  200      param_buffers.push_back(empty_buffer);
 
  202      param_buffers.push_back(buffer.data());
 
  206  using OidList = std::vector<Oid>;
 
  207  using BufferType = std::vector<
char>;
 
  208  using ParameterList = std::vector<BufferType>;
 
  209  using IntList = std::vector<
int>;
 
  211  static constexpr const char* empty_buffer = 
"";
 
  213  ParameterList parameters;  
 
  215  std::vector<
const char*> param_buffers;
 
  216  IntList param_lengths;
 
  217  IntList param_formats;