pg_async
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
query.inl
Go to the documentation of this file.
1 /*
2  * query.inl
3  *
4  * Created on: Jul 20, 2015
5  * Author: zmij
6  */
7 
8 #ifndef LIB_PG_ASYNC_INCLUDE_TIP_DB_PG_QUERY_INL_
9 #define LIB_PG_ASYNC_INCLUDE_TIP_DB_PG_QUERY_INL_
10 
11 #include <tip/db/pg/query.hpp>
12 #include <tip/util/meta_helpers.hpp>
14 
15 namespace tip {
16 namespace db {
17 namespace pg {
18 
19 namespace detail {
20 
21 template < size_t Index, typename T >
22 struct nth_param {
23  enum {
24  index = Index
25  };
26  typedef T type;
27  typedef io::traits::best_formatter<type> best_formatter;
28  static constexpr protocol_data_format data_format = best_formatter::value;
29  typedef typename best_formatter::type formatter_type;
30 
31  static bool
32  write_format( std::vector<byte>& buffer )
33  {
34  return io::protocol_write< BINARY_DATA_FORMAT >(buffer, (smallint)data_format);
35  }
36 
37  static bool
38  write_value (std::vector<byte>& buffer, type const& value)
39  {
40  // TODO Reserve space
41  size_t buffer_pos = buffer.size();
42  // space for length
43  buffer.resize(buffer.size() + sizeof(integer));
44  size_t prev_size = buffer.size();
45  io::protocol_write< data_format >(buffer, value);
46  integer len = buffer.size() - prev_size;
47  // write length
48  std::vector<byte>::iterator sz_iter = buffer.begin() +
49  buffer_pos;
50  io::protocol_write< BINARY_DATA_FORMAT >( sz_iter, len );
51  integer written(0);
52  io::protocol_read< BINARY_DATA_FORMAT > (sz_iter, sz_iter + sizeof(integer), written);
53  assert(written == len && "Length is written ok");
54  return true;
55  }
56 
57  static integer
58  size(type const& value)
59  {
60  return io::protocol_writer< data_format >(value).size() + sizeof(integer);
61  }
62 };
63 
64 template < size_t Index, typename T >
65 struct nth_param < Index, boost::optional< T > > {
66  enum {
67  index = Index
68  };
69  typedef T type;
70  typedef io::traits::best_formatter<type> best_formatter;
71  static constexpr protocol_data_format data_format = best_formatter::value;
72  typedef typename best_formatter::type formatter_type;
73 
74  static bool
75  write_format( std::vector<byte>& buffer )
76  {
77  return io::protocol_write< BINARY_DATA_FORMAT >(buffer, (smallint)data_format);
78  }
79 
80  static bool
81  write_value (std::vector<byte>& buffer, boost::optional<type> const& value)
82  {
83  if (value) {
84  return nth_param< Index, T >::write_value( buffer, *value );
85  }
86  // NULL value
87  return io::protocol_write< BINARY_DATA_FORMAT >( buffer, (integer)-1 );
88  }
89 };
90 
91 
92 template < size_t Index, typename ... T >
93 struct format_selector;
94 
95 template < typename T >
96 struct format_selector< 0, T > {
97  enum {
98  index = 0
99  };
100  typedef T type;
101  typedef io::traits::best_formatter<type> best_formatter;
102  typedef typename best_formatter::type formatter_type;
103 
104  typedef io::traits::cpppg_data_mapping< T > data_mapping;
105 
106  static constexpr protocol_data_format data_format = best_formatter::value;
107  static constexpr bool single_format = true;
108  enum {
109  type_oid = data_mapping::type_oid
110  };
111 
112  static void
113  write_type(type_oid_sequence& param_types)
114  {
115  static_assert( io::traits::cpppg_data_mapping< T >::type_oid != oids::type::unknown,
116  "Parameter type doesn't have a PostgreSQL typeoid mapping" );
117  param_types.push_back((oids::type::oid_type)type_oid);
118  }
119  static void
120  write_format( std::vector<byte>& buffer )
121  {
122  io::protocol_write< BINARY_DATA_FORMAT >(buffer, (smallint)data_format);
123  }
124 
125  static void
126  write_param_value( std::vector<byte>& buffer, type const& value)
127  {
128  nth_param<index, T>::write_value(buffer, value);
129  }
130 
131  static size_t
132  size( type const& value )
133  {
134  return nth_param< index, T >::size(value);
135  }
136 };
137 
138 template < size_t N, typename T, typename ... Y >
139 struct format_selector< N, T, Y ... > {
140  enum {
141  index = N
142  };
143  typedef T type;
144  typedef io::traits::best_formatter<type> best_formatter;
145  typedef typename best_formatter::type formatter_type;
146 
147  typedef format_selector< N - 1, Y ...> next_param_type;
148 
149  typedef io::traits::cpppg_data_mapping< T > data_mapping;
150 
151  static constexpr protocol_data_format data_format = best_formatter::value;
152  static constexpr bool single_format =
153  next_param_type::single_format &&
154  next_param_type::data_format == data_format;
155  enum {
156  type_oid = data_mapping::type_oid
157  };
158 
159  static void
160  write_type(type_oid_sequence& param_types)
161  {
162  static_assert( io::traits::cpppg_data_mapping< T >::type_oid != oids::type::unknown,
163  "Parameter type doesn't have a PostgreSQL typeoid mapping" );
164  param_types.push_back((oids::type::oid_type)type_oid);
165  next_param_type::write_type(param_types);
166  }
167  static void
168  write_format( std::vector<byte>& buffer )
169  {
170  io::protocol_write< BINARY_DATA_FORMAT >(buffer, (smallint)data_format);
171  next_param_type::write_format(buffer);
172  }
173 
174  static void
175  write_param_value( std::vector<byte>& buffer, type const& value,
176  Y const& ... next )
177  {
178  nth_param<index, T>::write_value(buffer, value);
179  next_param_type::write_param_value(buffer, next ...);
180  }
181  static size_t
182  size( type const& value, Y const& ... next )
183  {
184  return nth_param< index, T >::size(value) + next_param_type::size(next ...);
185  }
186 };
187 
191 template < typename ... T >
192 struct is_text_format {
193  enum {
194  size = sizeof ... (T),
195  last_index = size - 1
196  };
197  typedef format_selector< last_index, T... > last_selector;
198  static constexpr bool value = last_selector::single_format &&
199  last_selector::data_format == TEXT_DATA_FORMAT;
200 };
201 
202 
203 
204 template < bool, typename IndexTuple, typename ... T >
205 struct param_format_builder;
206 
210 template < size_t ... Indexes, typename ... T >
211 struct param_format_builder< true, util::indexes_tuple< Indexes ... >, T ... > {
212  enum {
213  size = sizeof ... (T),
214  last_index = size - 1
215  };
216 
217  typedef format_selector< last_index, T... > first_selector;
218  static constexpr protocol_data_format data_format = first_selector::data_format;
219 
220 
221  bool
222  static write_params( type_oid_sequence& param_types, std::vector<byte>& buffer,
223  T const& ... args )
224  {
225  param_types.reserve(size);
226  first_selector::write_type(param_types);
227 
228  size_t sz = sizeof(smallint) * 2 //text data format + count of params
229  + first_selector::size(args ...); // size of params
230  buffer.reserve(sz);
231 
232  io::protocol_write<BINARY_DATA_FORMAT>(buffer, (smallint)data_format);
233  io::protocol_write<BINARY_DATA_FORMAT>(buffer, (smallint)size);
234  first_selector::write_param_value(buffer, args ...);
235  return true;
236  }
237 
238 };
239 
243 template < size_t ... Indexes, typename ... T >
244 struct param_format_builder< false, util::indexes_tuple< Indexes ... >, T ... > {
245  enum {
246  size = sizeof ... (T),
247  last_index = size - 1
248  };
249 
250  typedef format_selector< last_index, T... > first_selector;
251  static constexpr protocol_data_format data_format = first_selector::data_format;
252 
253 
254  bool
255  static write_params( type_oid_sequence& param_types, std::vector<byte>& buffer,
256  T const& ... args )
257  {
258  param_types.reserve(size);
259  first_selector::write_type(param_types);
260 
261  size_t sz = sizeof(smallint) * 2 // data format count + count of params
262  + sizeof(smallint) * size // data formats
263  + first_selector::size(args ...); // params
264  buffer.reserve(sz);
265 
266  io::protocol_write<BINARY_DATA_FORMAT>(buffer, (smallint)size);
267  first_selector::write_format(buffer);
268  io::protocol_write<BINARY_DATA_FORMAT>(buffer, (smallint)size);
269  first_selector::write_param_value(buffer, args ...);
270  return true;
271  }
272 
273 };
274 
275 
276 template < typename ... T >
277 struct param_formatter : param_format_builder <
278  is_text_format< T ... >::value,
279  typename util::index_builder< sizeof ... (T) >::type,
280  T ... > {
281 
282 };
283 
284 struct ___no_binary_format {};
285 static_assert( !is_text_format< smallint, integer, bigint, ___no_binary_format >::value,
286  "No single format");
287 
288 static_assert( !is_text_format< smallint, integer, bigint >::value,
289  "Single format for integral types" );
290 static_assert( param_formatter< smallint, integer, bigint >::data_format
292  "Binary format for integral types");
293 
294 template < typename ... T >
295 void
296 write_params(std::vector< oids::type::oid_type >& param_types,
297  std::vector<byte>& buffer, T const& ... params)
298 {
299  param_formatter< T ... >::write_params(param_types, buffer, params ...);
300 }
301 
302 } // namespace detail
303 
304 template < typename ... T >
305 query::query(dbalias const& alias, std::string const& expression,
306  T const& ... params)
307  : pimpl_(create_impl(alias, expression, params ...))
308 {
309 }
310 
311 template < typename ... T >
313  T const& ... params)
314  : pimpl_(create_impl(t, expression, params ... ))
315 {
316 }
317 
318 template < typename ... T >
319 query::pimpl
320 query::create_impl(dbalias const& alias, std::string const& expression,
321  T const& ... params)
322 {
323  type_oid_sequence ptypes;
324  params_buffer buf;
325  detail::write_params(ptypes, buf, params ...);
326  return create_impl(alias, expression, std::move(ptypes), std::move(buf));
327 }
328 
329 template < typename ... T >
330 query::pimpl
331 query::create_impl(transaction_ptr tran, std::string const& expression,
332  T const& ... params)
333 {
334  type_oid_sequence ptypes;
335  params_buffer buf;
336  detail::write_params(ptypes, buf, params ...);
337  return create_impl(tran, expression, std::move(ptypes), std::move(buf));
338 }
339 
340 
341 template < typename ... T >
342 query&
343 query::bind(T const& ... params)
344 {
345  // 1. Write format codes
346  // - detect if all of param types have binary formatters
347  // - write a binary format code (1) if all have binary formatters
348  // - write format codes for each param
349  // - evaluate buffer length
350  // 2. Params
351  // - write the number of params
352  // - write each param preceded by it's length
353  type_oid_sequence& ptypes = param_types();
354  ptypes.clear();
355  params_buffer& buf = buffer();
356  buf.clear();
357  detail::write_params(ptypes, buf, params ...);
358  return *this;
359 }
360 
361 } // namespace pg
362 } // namespace db
363 } // namespace tip
364 
365 #endif /* LIB_PG_ASYNC_INCLUDE_TIP_DB_PG_QUERY_INL_ */
query & bind()
Mark the query as prepared statement.
Short unique string to refer a database. Signature structure, to pass instead of connection string...
Definition: common.hpp:209
std::shared_ptr< transaction > transaction_ptr
Definition: common.hpp:340
protocol_data_format
Definition: common.hpp:283
static constexpr protocol_data_format value
query(dbalias const &alias, std::string const &expression)
Construct a query.
boost::int_t< 32 >::exact integer
4-byte integer, to match PostgreSQL integer and serial types
Definition: common.hpp:162
boost::int_t< 16 >::exact smallint
2-byte integer, to match PostgreSQL smallint and smallserial types
Definition: common.hpp:154
BINARY_DATA_FORMAT.
Definition: common.hpp:285
TEXT_DATA_FORMAT.
Definition: common.hpp:284
void write_params(std::vector< oids::type::oid_type > &param_types, std::vector< byte > &buffer, T const &...params)
Definition: query.inl:296
std::vector< oids::type::oid_type > type_oid_sequence
Definition: common.hpp:346