OZO 「お象」
Boost.Asio and libpq based asynchronous PostgreSQL unofficial header-only C++17 client library.
binary_query.h
1 #pragma once
2 
3 #include <ozo/ext/std.h>
4 #include <ozo/ext/boost.h>
5 #include <ozo/io/send.h>
6 #include <ozo/io/array.h>
7 #include <ozo/io/composite.h>
8 #include <ozo/core/concept.h>
9 #include <ozo/query.h>
10 #include <ozo/type_traits.h>
11 #include <ozo/optional.h>
12 #include <ozo/pg/types.h>
13 
14 #include <boost/hana/for_each.hpp>
15 #include <boost/hana/tuple.hpp>
16 #include <boost/hana/ext/std/array.hpp>
17 
18 #include <libpq-fe.h>
19 
20 #include <array>
21 #include <iterator>
22 #include <memory>
23 #include <string_view>
24 #include <vector>
25 
26 namespace ozo {
27 
37 class binary_query {
38 public:
48  template <class Text, class Params, class OidMap, class Allocator = std::allocator<char>>
49  binary_query(Text text, const Params& params, const OidMap& oid_map, const Allocator& allocator = Allocator{})
50  : impl{std::allocate_shared<impl_type<Text, Params, OidMap, Allocator>>(
51  allocator, std::move(text), params, oid_map, allocator
52  )} {}
53 
59  const char* text() const noexcept {
60  return impl->text();
61  }
62 
68  const oid_t* types() const noexcept {
69  return impl->types();
70  }
71 
77  const int* formats() const noexcept {
78  return impl->formats();
79  }
80 
87  const int* lengths() const noexcept {
88  return impl->lengths();
89  }
90 
96  const char* const* values() const noexcept {
97  return impl->values();
98  }
99 
105  std::ptrdiff_t params_count() const noexcept {
106  return impl->params_count();
107  }
108 
109 private:
110  static constexpr auto binary_format = 1;
111 
112  struct interface {
113  virtual const char* text() const noexcept = 0;
114  virtual const oid_t* types() const noexcept = 0;
115  virtual const int* formats() const noexcept = 0;
116  virtual const int* lengths() const noexcept = 0;
117  virtual const char* const* values() const noexcept = 0;
118  virtual std::ptrdiff_t params_count() const noexcept = 0;
119  virtual ~interface() = default;
120  };
121 
122  template <class Text, class Params, class OidMap, class Allocator = std::allocator<char>>
123  struct impl_type final : interface {
124  static_assert(ozo::HanaSequence<Params>, "Params should be Hana.Sequence");
125  static_assert(ozo::OidMap<OidMap>, "OidMap should model ozo::OidMap");
126  static_assert(ozo::QueryText<Text>, "Text should model ozo::QueryText concept");
127 
128  using allocator_type = std::conditional_t<
129  std::is_same_v<typename Allocator::value_type, char>,
130  Allocator,
131  typename Allocator::template rebind<char>::other>;
132  using buffer_type = std::vector<char, allocator_type>;
133  using oid_map_type = OidMap;
134  using text_type = std::decay_t<Text>;
135  using params_type = Params;
136 
137  static constexpr auto params_count_ = decltype(hana::length(std::declval<params_type>()))::value;
138 
139  text_type text_;
140  buffer_type buffer_;
141  std::array<oid_t, params_count_> types_;
142  std::array<int, params_count_> formats_;
143  std::array<int, params_count_> lengths_;
144  std::array<const char*, params_count_> values_;
145 
146  impl_type(Text text, const Params& params,
147  const OidMap& oid_map, const Allocator& allocator)
148  : text_(std::move(text)), buffer_(allocator) {
149  formats_.fill(binary_format);
150 
151  const auto range = hana::to_tuple(hana::make_range(hana::size_c<0>, hana::size_c<params_count_>));
152 
153  hana::for_each(range, [&] (auto i) {
154  lengths_[i] = std::max(0, size_of(params[i]));
155  types_[i] = type_oid(oid_map, params[i]);
156  });
157 
158  buffer_.reserve(hana::unpack(lengths_, [](auto ...x) {return (x + ... + 0);}));
159 
160  ozo::ostream os(buffer_);
161 
162  hana::for_each(params, [&] (auto& param) { send(os, oid_map, param);});
163 
164  std::size_t offset = 0;
165  hana::for_each(range, [&] (auto i) {
166  values_[i] = lengths_[i] ? std::data(buffer_) + offset : nullptr;
167  offset += lengths_[i];
168  });
169  }
170 
171  impl_type(const impl_type&) = delete;
172  impl_type(impl_type&&) = delete;
173 
174  const char* text() const noexcept override {
175  return to_const_char(text_);
176  }
177 
178  const oid_t* types() const noexcept override {
179  return std::data(types_);
180  }
181 
182  const int* formats() const noexcept override {
183  return std::data(formats_);
184  }
185 
186  const int* lengths() const noexcept override {
187  return std::data(lengths_);
188  }
189 
190  const char* const* values() const noexcept override {
191  return std::data(values_);
192  }
193 
194  std::ptrdiff_t params_count() const noexcept override {
195  return params_count_;
196  }
197  };
198 
199  std::shared_ptr<const interface> impl;
200 };
201 
202 namespace detail {
203 struct no_binary_query_conversion {};
204 } // namespace detail
205 
206 template <typename T, typename = hana::when<true>>
207 struct to_binary_query_impl : detail::no_binary_query_conversion {
208  template <typename OidMap, typename Alloc>
209  static auto apply(const T&, const OidMap&, const Alloc&) {
210  static_assert(std::is_void_v<to_binary_query_impl>, "no conversion to the binary_query is defined");
211  }
212 };
213 
214 template <typename T>
215 using is_binary_query_convertible = typename std::negation<typename std::is_base_of<detail::no_binary_query_conversion, T>::type>::type;
216 
217 template <typename T>
218 inline constexpr auto is_binary_query_convertible_v = is_binary_query_convertible<T>::value;
219 
275 template <typename T>
277 inline constexpr auto BinaryQueryConvertible = is_binary_query_convertible_v<std::decay_t<T>>;
279 
280 template <typename T>
281 struct to_binary_query_impl<T, hana::when<Query<T>>> {
282  template <typename OidMap, typename Alloc>
283  static binary_query apply(const T& query, const OidMap& oid_map, const Alloc& allocator) {
284  return binary_query(get_query_text(query), get_query_params(query), oid_map, allocator);
285  }
286 };
287 
288 template <>
289 struct to_binary_query_impl<binary_query> {
290  template <typename OidMap, typename Alloc>
291  static binary_query apply(const binary_query& query, const OidMap&, const Alloc&) {
292  return query;
293  }
294 };
295 
313 template <typename BinaryQueryConvertible, typename OidMap, typename Allocator = std::allocator<char>>
315  const OidMap& oid_map, const Allocator& allocator = Allocator{}) {
316  return to_binary_query_impl<BinaryQueryConvertible>::apply(query, oid_map, allocator);
317 }
318 
319 } // namespace ozo
ozo::size_of
constexpr size_type size_of(const T &v)
Returns size of object binary representation in bytes.
Definition: size_of.h:105
ozo::binary_query::binary_query
binary_query(Text text, const Params &params, const OidMap &oid_map, const Allocator &allocator=Allocator{})
Definition: binary_query.h:49
ozo::send
ostream & send(ostream &out, const OidMap &oid_map, const In &in)
Send object to an output stream.
Definition: send.h:93
ozo::get_query_params
constexpr auto get_query_params(Query &&query)
Get the query parameters.
ozo::binary_query::formats
const int * formats() const noexcept
Definition: binary_query.h:77
ozo::OidMap
constexpr auto OidMap
Map of C++ types to corresponding PostgreSQL types OIDs.
Definition: type_traits.h:534
ozo::binary_query::params_count
std::ptrdiff_t params_count() const noexcept
Definition: binary_query.h:105
ozo::binary_query::text
const char * text() const noexcept
Definition: binary_query.h:59
ozo::binary_query
Binary protocol query representation.
Definition: binary_query.h:37
ozo::value
Database request result value proxy.
Definition: result.h:25
ozo::binary_query::values
const char *const * values() const noexcept
Definition: binary_query.h:96
ozo::type_oid
oid_t type_oid(const OidMap &map) noexcept
Function returns oid for a type from #OidMap.
ozo::get_query_text
constexpr auto get_query_text(Query &&query)
Get the query text object.
ozo::to_const_char
constexpr auto to_const_char(const T &text) noexcept
Convert QueryText to const char*.
ozo::binary_query::types
const oid_t * types() const noexcept
Definition: binary_query.h:68
BinaryQueryConvertible
Concept of a type that is convertible to ozo::binary_query
ozo::oid_t
::Oid oid_t
PostgreSQL OID type - object identifier.
Definition: type_traits.h:70
ozo::binary_query::lengths
const int * lengths() const noexcept
Definition: binary_query.h:87
ozo::to_binary_query
binary_query to_binary_query(const BinaryQueryConvertible &query, const OidMap &oid_map, const Allocator &allocator=Allocator{})
Convert a query object to the binary representation.
Definition: binary_query.h:314