libdballe  7.19
postgresql.h
Go to the documentation of this file.
1 
4 #ifndef DBALLE_SQL_POSTGRESQL_H
5 #define DBALLE_SQL_POSTGRESQL_H
6 
7 #include <dballe/sql/sql.h>
8 #include <libpq-fe.h>
9 #include <arpa/inet.h>
10 #include <vector>
11 
12 namespace dballe {
13 namespace sql {
14 
18 struct error_postgresql : public error_db
19 {
20  std::string msg;
21 
22  error_postgresql(PGconn* db, const std::string& msg);
23  error_postgresql(PGresult* db, const std::string& msg);
24  error_postgresql(const std::string& dbmsg, const std::string& msg);
25  ~error_postgresql() throw () {}
26 
27  const char* what() const noexcept override { return msg.c_str(); }
28 
29  static void throwf(PGconn* db, const char* fmt, ...) WREPORT_THROWF_ATTRS(2, 3);
30  static void throwf(PGresult* db, const char* fmt, ...) WREPORT_THROWF_ATTRS(2, 3);
31 };
32 
33 namespace postgresql {
34 
35 int64_t encode_datetime(const Datetime& arg);
36 int64_t encode_int64_t(int64_t arg);
37 
39 template<typename... ARGS> struct Params
40 {
41  static const int count = sizeof...(ARGS);
42  const char* args[sizeof...(ARGS)];
43  int lengths[sizeof...(ARGS)];
44  int formats[sizeof...(ARGS)];
45  void* local[sizeof...(ARGS)];
46 
47  Params(const ARGS&... args)
48  {
49  _add(0, args...);
50  }
51  ~Params()
52  {
53  for (auto& i: local)
54  free(i);
55  }
56 
57  Params(const Params&) = delete;
58  Params(const Params&&) = delete;
59  Params& operator=(const Params&) = delete;
60  Params& operator=(const Params&&) = delete;
61 
62 protected:
64  void _add(unsigned pos)
65  {
66  }
67 
69  template<typename... REST>
70  void _add(unsigned pos, std::nullptr_t arg, const REST&... rest)
71  {
72  local[pos] = nullptr;
73  args[pos] = nullptr;
74  lengths[pos] = 0;
75  formats[pos] = 0;
76  _add(pos + 1, rest...);
77  }
78 
80  template<typename... REST>
81  void _add(unsigned pos, int32_t arg, const REST&... rest)
82  {
83  local[pos] = malloc(sizeof(int32_t));
84  *(int32_t*)local[pos] = (int32_t)htonl((uint32_t)arg);
85  args[pos] = (const char*)local[pos];
86  lengths[pos] = sizeof(int32_t);
87  formats[pos] = 1;
88  _add(pos + 1, rest...);
89  }
90 
92  template<typename... REST>
93  void _add(unsigned pos, uint64_t arg, const REST&... rest)
94  {
95  local[pos] = malloc(sizeof(int64_t));
96  *(int64_t*)local[pos] = encode_int64_t(arg);
97  args[pos] = (const char*)local[pos];
98  lengths[pos] = sizeof(int64_t);
99  formats[pos] = 1;
100  _add(pos + 1, rest...);
101  }
102 
104  template<typename... REST>
105  void _add(unsigned pos, const char* arg, const REST&... rest)
106  {
107  local[pos] = nullptr;
108  args[pos] = arg;
109  lengths[pos] = 0;
110  formats[pos] = 0;
111  _add(pos + 1, rest...);
112  }
113 
115  template<typename... REST>
116  void _add(unsigned pos, const std::string& arg, const REST&... rest)
117  {
118  local[pos] = nullptr;
119  args[pos] = arg.data();
120  lengths[pos] = arg.size();
121  formats[pos] = 0;
122  _add(pos + 1, rest...);
123  }
124 
126  template<typename... REST>
127  void _add(unsigned pos, const std::vector<uint8_t>& arg, const REST&... rest)
128  {
129  local[pos] = nullptr;
130  args[pos] = (const char*)arg.data();
131  lengths[pos] = arg.size();
132  formats[pos] = 1;
133  _add(pos + 1, rest...);
134  }
135 
137  template<typename... REST>
138  void _add(unsigned pos, const Datetime& arg, const REST&... rest)
139  {
140  local[pos] = malloc(sizeof(int64_t));
141  *(int64_t*)local[pos] = encode_datetime(arg);
142  args[pos] = (const char*)local[pos];
143  lengths[pos] = sizeof(int64_t);
144  formats[pos] = 1;
145  _add(pos + 1, rest...);
146  }
147 };
148 
150 struct Result
151 {
152  PGresult* res;
153 
154  Result() : res(nullptr) {}
155  Result(PGresult* res) : res(res) {}
156  ~Result() { PQclear(res); }
157 
159  Result(Result&& o) : res(o.res) { o.res = nullptr; }
160  Result& operator=(Result&& o)
161  {
162  if (this == &o) return *this;
163  PQclear(res);
164  res = o.res;
165  o.res = nullptr;
166  return *this;
167  }
168 
169  operator bool() const { return res != nullptr; }
170  operator PGresult*() { return res; }
171  operator const PGresult*() const { return res; }
172 
174  void expect_no_data(const std::string& query);
175 
177  void expect_result(const std::string& query);
178 
180  void expect_one_row(const std::string& query);
181 
183  void expect_success(const std::string& query);
184 
186  unsigned rowcount() const { return PQntuples(res); }
187 
189  bool is_null(unsigned row, unsigned col) const
190  {
191  return PQgetisnull(res, row, col);
192  }
193 
195  bool get_bool(unsigned row, unsigned col) const
196  {
197  char* val = PQgetvalue(res, row, col);
198  return *val;
199  }
200 
202  uint16_t get_int2(unsigned row, unsigned col) const
203  {
204  char* val = PQgetvalue(res, row, col);
205  return ntohs(*(uint16_t*)val);
206  }
207 
209  uint32_t get_int4(unsigned row, unsigned col) const
210  {
211  char* val = PQgetvalue(res, row, col);
212  return ntohl(*(uint32_t*)val);
213  }
214 
216  uint64_t get_int8(unsigned row, unsigned col) const;
217 
219  std::vector<uint8_t> get_bytea(unsigned row, unsigned col) const;
220 
222  const char* get_string(unsigned row, unsigned col) const
223  {
224  return PQgetvalue(res, row, col);
225  }
226 
228  Datetime get_timestamp(unsigned row, unsigned col) const;
229 
230  // Prevent copy
231  Result(const Result&) = delete;
232  Result& operator=(const Result&) = delete;
233 };
234 
235 }
236 
237 
240 {
241 protected:
243  PGconn* db = nullptr;
244 
245 protected:
246  void init_after_connect();
247 
248 public:
251  PostgreSQLConnection(const PostgreSQLConnection&&) = delete;
253 
254  PostgreSQLConnection& operator=(const PostgreSQLConnection&) = delete;
255 
256  operator PGconn*() { return db; }
257 
264  void open_url(const std::string& connection_string);
265  void open_test();
266 
267  std::unique_ptr<Transaction> transaction() override;
268 
270  void prepare(const std::string& name, const std::string& query);
271 
272  postgresql::Result exec_unchecked(const char* query)
273  {
274  if (profile) ++profile_query_count;
275  return PQexecParams(db, query, 0, nullptr, nullptr, nullptr, nullptr, 1);
276  }
277 
278  postgresql::Result exec_unchecked(const std::string& query)
279  {
280  if (profile) ++profile_query_count;
281  return PQexecParams(db, query.c_str(), 0, nullptr, nullptr, nullptr, nullptr, 1);
282  }
283 
284  template<typename STRING>
285  void exec_no_data(STRING query)
286  {
287  postgresql::Result res(exec_unchecked(query));
288  res.expect_no_data(query);
289  }
290 
291  template<typename STRING>
292  postgresql::Result exec(STRING query)
293  {
294  postgresql::Result res(exec_unchecked(query));
295  res.expect_result(query);
296  return res;
297  }
298 
299  template<typename STRING>
300  postgresql::Result exec_one_row(STRING query)
301  {
302  postgresql::Result res(exec_unchecked(query));
303  res.expect_one_row(query);
304  return res;
305  }
306 
307  template<typename ...ARGS>
308  postgresql::Result exec_unchecked(const char* query, ARGS... args)
309  {
310  postgresql::Params<ARGS...> params(args...);
311  if (profile) ++profile_query_count;
312  return PQexecParams(db, query, params.count, nullptr, params.args, params.lengths, params.formats, 1);
313  }
314 
315  template<typename ...ARGS>
316  postgresql::Result exec_unchecked(const std::string& query, ARGS... args)
317  {
318  postgresql::Params<ARGS...> params(args...);
319  if (profile) ++profile_query_count;
320  return PQexecParams(db, query.c_str(), params.count, nullptr, params.args, params.lengths, params.formats, 1);
321  }
322 
323  template<typename STRING, typename ...ARGS>
324  void exec_no_data(STRING query, ARGS... args)
325  {
326  postgresql::Result res(exec_unchecked(query, args...));
327  res.expect_no_data(query);
328  }
329 
330  template<typename STRING, typename ...ARGS>
331  postgresql::Result exec(STRING query, ARGS... args)
332  {
333  postgresql::Result res(exec_unchecked(query, args...));
334  res.expect_result(query);
335  return res;
336  }
337 
338  template<typename STRING, typename ...ARGS>
339  postgresql::Result exec_one_row(STRING query, ARGS... args)
340  {
341  postgresql::Result res(exec_unchecked(query, args...));
342  res.expect_one_row(query);
343  return res;
344  }
345 
346  postgresql::Result exec_prepared_unchecked(const char* name)
347  {
348  if (profile) ++profile_query_count;
349  return PQexecPrepared(db, name, 0, nullptr, nullptr, nullptr, 1);
350  }
351 
352  postgresql::Result exec_prepared_unchecked(const std::string& name)
353  {
354  if (profile) ++profile_query_count;
355  return PQexecPrepared(db, name.c_str(), 0, nullptr, nullptr, nullptr, 1);
356  }
357 
358  template<typename STRING>
359  void exec_prepared_no_data(STRING name)
360  {
361  postgresql::Result res(exec_prepared_unchecked(name));
362  res.expect_no_data(name);
363  }
364 
365  template<typename STRING>
366  postgresql::Result exec_prepared(STRING name)
367  {
368  postgresql::Result res(exec_prepared_unchecked(name));
369  res.expect_result(name);
370  return res;
371  }
372 
373  template<typename STRING>
374  postgresql::Result exec_prepared_one_row(STRING name)
375  {
376  postgresql::Result res(exec_prepared_unchecked(name));
377  res.expect_one_row(name);
378  return res;
379  }
380 
381  template<typename ...ARGS>
382  postgresql::Result exec_prepared_unchecked(const char* name, ARGS... args)
383  {
384  postgresql::Params<ARGS...> params(args...);
385  if (profile) ++profile_query_count;
386  return PQexecPrepared(db, name, params.count, params.args, params.lengths, params.formats, 1);
387  }
388 
389  template<typename ...ARGS>
390  postgresql::Result exec_prepared_unchecked(const std::string& name, ARGS... args)
391  {
392  postgresql::Params<ARGS...> params(args...);
393  if (profile) ++profile_query_count;
394  return PQexecPrepared(db, name.c_str(), params.count, params.args, params.lengths, params.formats, 1);
395  }
396 
397  template<typename STRING, typename ...ARGS>
398  void exec_prepared_no_data(STRING name, ARGS... args)
399  {
400  postgresql::Result res(exec_prepared_unchecked(name, args...));
401  res.expect_no_data(name);
402  }
403 
404  template<typename STRING, typename ...ARGS>
405  postgresql::Result exec_prepared(STRING name, ARGS... args)
406  {
407  postgresql::Result res(exec_prepared_unchecked(name, args...));
408  res.expect_result(name);
409  return res;
410  }
411 
412  template<typename STRING, typename ...ARGS>
413  postgresql::Result exec_prepared_one_row(STRING name, ARGS... args)
414  {
415  postgresql::Result res(exec_prepared_unchecked(name, args...));
416  res.expect_one_row(name);
417  return res;
418  }
419 
421  void cancel_running_query_nothrow() noexcept;
422 
424  void discard_all_input_nothrow() noexcept;
425 
426  bool has_table(const std::string& name) override;
427  std::string get_setting(const std::string& key) override;
428  void set_setting(const std::string& key, const std::string& value) override;
429  void drop_settings() override;
430  void execute(const std::string& query) override;
431  void explain(const std::string& query, FILE* out) override;
432 
436  void drop_table_if_exists(const char* name);
437 
439  int changes();
440 
442  void pqexec(const std::string& query);
443 
450  void pqexec_nothrow(const std::string& query) noexcept;
451 
453  void run_single_row_mode(const std::string& query_desc, std::function<void(const postgresql::Result&)> dest);
454 
456  void append_escaped(Querybuf& qb, const char* str);
457 
459  void append_escaped(Querybuf& qb, const std::string& str);
460 
462  void append_escaped(Querybuf& qb, const std::vector<uint8_t>& buf);
463 };
464 
465 }
466 }
467 #endif
468 
Database connection.
Definition: postgresql.h:239
Result(Result &&o)
Implement move.
Definition: postgresql.h:159
void _add(unsigned pos, const char *arg, const REST &...rest)
Fill in the argument structures.
Definition: postgresql.h:105
Argument list for PQexecParams built at compile time.
Definition: postgresql.h:39
bool is_null(unsigned row, unsigned col) const
Check if a result value is null.
Definition: postgresql.h:189
void _add(unsigned pos)
Terminating condition for compile-time arg expansion.
Definition: postgresql.h:64
Copyright (C) 2008–2010 ARPA-SIM urpsim@smr.arpa.emr.it
Definition: cmdline.h:17
void _add(unsigned pos, const Datetime &arg, const REST &...rest)
Fill in the argument structures.
Definition: postgresql.h:138
uint16_t get_int2(unsigned row, unsigned col) const
Return a result value, transmitted in binary as a 2 bit integer.
Definition: postgresql.h:202
void _add(unsigned pos, const std::vector< uint8_t > &arg, const REST &...rest)
Fill in the argument structures.
Definition: postgresql.h:127
Definition: sql.h:59
Wrap a PGresult, taking care of its memory management.
Definition: postgresql.h:150
bool get_bool(unsigned row, unsigned col) const
Return a result value, transmitted in binary as a byte (?)
Definition: postgresql.h:195
uint32_t get_int4(unsigned row, unsigned col) const
Return a result value, transmitted in binary as a 4 bit integer.
Definition: postgresql.h:209
Report an PostgreSQL error.
Definition: postgresql.h:18
Common infrastructure for talking with SQL databases.
Error in case of failed database operations.
Definition: error.h:21
unsigned rowcount() const
Get the number of rows in the result.
Definition: postgresql.h:186
Date and time.
Definition: types.h:158
void _add(unsigned pos, std::nullptr_t arg, const REST &...rest)
Fill in the argument structures.
Definition: postgresql.h:70
void _add(unsigned pos, uint64_t arg, const REST &...rest)
Fill in the argument structures.
Definition: postgresql.h:93
#define WREPORT_THROWF_ATTRS(a, b)
const char * get_string(unsigned row, unsigned col) const
Return a result value, transmitted as a string.
Definition: postgresql.h:222
void _add(unsigned pos, const std::string &arg, const REST &...rest)
Fill in the argument structures.
Definition: postgresql.h:116
void _add(unsigned pos, int32_t arg, const REST &...rest)
Fill in the argument structures.
Definition: postgresql.h:81
String buffer for composing database queries.
Definition: querybuf.h:15