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