libdballe  7.6
postgresql/internals.h
1 /*
2  * db/sqlite/internals - Implementation infrastructure for the PostgreSQL DB connection
3  *
4  * Copyright (C) 2015 ARPA-SIM <urpsim@smr.arpa.emr.it>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18  *
19  * Author: Enrico Zini <enrico@enricozini.com>
20  */
21 
22 #ifndef DBALLE_DB_POSTGRESQL_INTERNALS_H
23 #define DBALLE_DB_POSTGRESQL_INTERNALS_H
24 
25 #include <dballe/db/db.h>
26 #include <dballe/db/sql.h>
27 #include <libpq-fe.h>
28 #include <arpa/inet.h>
29 
30 namespace dballe {
31 namespace db {
32 
36 struct error_postgresql : public db::error
37 {
38  std::string msg;
39 
44  error_postgresql(PGconn* db, const std::string& msg);
45  error_postgresql(PGresult* db, const std::string& msg);
46  error_postgresql(const std::string& dbmsg, const std::string& msg);
47  ~error_postgresql() throw () {}
48 
49  wreport::ErrorCode code() const throw () { return wreport::WR_ERR_ODBC; }
50 
51  virtual const char* what() const throw () { return msg.c_str(); }
52 
53  static void throwf(PGconn* db, const char* fmt, ...) WREPORT_THROWF_ATTRS(2, 3);
54  static void throwf(PGresult* db, const char* fmt, ...) WREPORT_THROWF_ATTRS(2, 3);
55 };
56 
57 namespace postgresql {
58 
59 int64_t encode_datetime(const Datetime& arg);
60 int64_t encode_int64_t(int64_t arg);
61 
63 template<typename... ARGS> struct Params
64 {
65  static const int count = sizeof...(ARGS);
66  const char* args[sizeof...(ARGS)];
67  int lengths[sizeof...(ARGS)];
68  int formats[sizeof...(ARGS)];
69  void* local[sizeof...(ARGS)];
70 
71  Params(const ARGS&... args)
72  {
73  _add(0, args...);
74  }
75  ~Params()
76  {
77  for (auto& i: local)
78  free(i);
79  }
80 
81  Params(const Params&) = delete;
82  Params(const Params&&) = delete;
83  Params& operator=(const Params&) = delete;
84  Params& operator=(const Params&&) = delete;
85 
86 protected:
88  void _add(unsigned pos)
89  {
90  }
91 
93  template<typename... REST>
94  void _add(unsigned pos, std::nullptr_t arg, const REST&... rest)
95  {
96  local[pos] = nullptr;
97  args[pos] = nullptr;
98  lengths[pos] = 0;
99  formats[pos] = 0;
100  _add(pos + 1, rest...);
101  }
102 
104  template<typename... REST>
105  void _add(unsigned pos, int32_t arg, const REST&... rest)
106  {
107  local[pos] = malloc(sizeof(int32_t));
108  *(int32_t*)local[pos] = (int32_t)htonl((uint32_t)arg);
109  args[pos] = (const char*)local[pos];
110  lengths[pos] = sizeof(int32_t);
111  formats[pos] = 1;
112  _add(pos + 1, rest...);
113  }
114 
116  template<typename... REST>
117  void _add(unsigned pos, uint64_t arg, const REST&... rest)
118  {
119  local[pos] = malloc(sizeof(int64_t));
120  *(int64_t*)local[pos] = encode_int64_t(arg);
121  args[pos] = (const char*)local[pos];
122  lengths[pos] = sizeof(int64_t);
123  formats[pos] = 1;
124  _add(pos + 1, rest...);
125  }
126 
128  template<typename... REST>
129  void _add(unsigned pos, const char* arg, const REST&... rest)
130  {
131  local[pos] = nullptr;
132  args[pos] = arg;
133  lengths[pos] = 0;
134  formats[pos] = 0;
135  _add(pos + 1, rest...);
136  }
137 
139  template<typename... REST>
140  void _add(unsigned pos, const std::string& arg, const REST&... rest)
141  {
142  local[pos] = nullptr;
143  args[pos] = arg.data();
144  lengths[pos] = arg.size();
145  formats[pos] = 0;
146  _add(pos + 1, rest...);
147  }
148 
150  template<typename... REST>
151  void _add(unsigned pos, const Datetime& arg, const REST&... rest)
152  {
153  local[pos] = malloc(sizeof(int64_t));
154  *(int64_t*)local[pos] = encode_datetime(arg);
155  args[pos] = (const char*)local[pos];
156  lengths[pos] = sizeof(int64_t);
157  formats[pos] = 1;
158  _add(pos + 1, rest...);
159  }
160 };
161 
163 struct Result
164 {
165  PGresult* res;
166 
167  Result() : res(nullptr) {}
168  Result(PGresult* res) : res(res) {}
169  ~Result() { PQclear(res); }
170 
172  Result(Result&& o) : res(o.res) { o.res = nullptr; }
173  Result& operator=(Result&& o)
174  {
175  if (this == &o) return *this;
176  PQclear(res);
177  res = o.res;
178  o.res = nullptr;
179  return *this;
180  }
181 
182  operator bool() const { return res != nullptr; }
183  operator PGresult*() { return res; }
184  operator const PGresult*() const { return res; }
185 
187  void expect_no_data(const std::string& query);
188 
190  void expect_result(const std::string& query);
191 
193  void expect_one_row(const std::string& query);
194 
196  void expect_success(const std::string& query);
197 
199  unsigned rowcount() const { return PQntuples(res); }
200 
202  bool is_null(unsigned row, unsigned col) const
203  {
204  return PQgetisnull(res, row, col);
205  }
206 
208  bool get_bool(unsigned row, unsigned col) const
209  {
210  char* val = PQgetvalue(res, row, col);
211  return *val;
212  }
213 
215  uint16_t get_int2(unsigned row, unsigned col) const
216  {
217  char* val = PQgetvalue(res, row, col);
218  return ntohs(*(uint16_t*)val);
219  }
220 
222  uint32_t get_int4(unsigned row, unsigned col) const
223  {
224  char* val = PQgetvalue(res, row, col);
225  return ntohl(*(uint32_t*)val);
226  }
227 
229  uint64_t get_int8(unsigned row, unsigned col) const;
230 
232  const char* get_string(unsigned row, unsigned col) const
233  {
234  return PQgetvalue(res, row, col);
235  }
236 
238  Datetime get_timestamp(unsigned row, unsigned col) const;
239 
240  // Prevent copy
241  Result(const Result&) = delete;
242  Result& operator=(const Result&) = delete;
243 };
244 
245 }
246 
247 
250 {
251 protected:
253  PGconn* db = nullptr;
254 
255 protected:
256  void init_after_connect();
257 
258 public:
261  PostgreSQLConnection(const PostgreSQLConnection&&) = delete;
263 
264  PostgreSQLConnection& operator=(const PostgreSQLConnection&) = delete;
265 
266  operator PGconn*() { return db; }
267 
274  void open_url(const std::string& connection_string);
275  void open_test();
276 
277  std::unique_ptr<Transaction> transaction() override;
278 
280  void prepare(const std::string& name, const std::string& query);
281 
282  postgresql::Result exec_unchecked(const char* query)
283  {
284  return PQexecParams(db, query, 0, nullptr, nullptr, nullptr, nullptr, 1);
285  }
286 
287  postgresql::Result exec_unchecked(const std::string& query)
288  {
289  return PQexecParams(db, query.c_str(), 0, nullptr, nullptr, nullptr, nullptr, 1);
290  }
291 
292  template<typename STRING>
293  void exec_no_data(STRING query)
294  {
295  postgresql::Result res(exec_unchecked(query));
296  res.expect_no_data(query);
297  }
298 
299  template<typename STRING>
300  postgresql::Result exec(STRING query)
301  {
302  postgresql::Result res(exec_unchecked(query));
303  res.expect_result(query);
304  return res;
305  }
306 
307  template<typename STRING>
308  postgresql::Result exec_one_row(STRING query)
309  {
310  postgresql::Result res(exec_unchecked(query));
311  res.expect_one_row(query);
312  return res;
313  }
314 
315  template<typename ...ARGS>
316  postgresql::Result exec_unchecked(const char* query, ARGS... args)
317  {
318  postgresql::Params<ARGS...> params(args...);
319  return PQexecParams(db, query, params.count, nullptr, params.args, params.lengths, params.formats, 1);
320  }
321 
322  template<typename ...ARGS>
323  postgresql::Result exec_unchecked(const std::string& query, ARGS... args)
324  {
325  postgresql::Params<ARGS...> params(args...);
326  return PQexecParams(db, query.c_str(), params.count, nullptr, params.args, params.lengths, params.formats, 1);
327  }
328 
329  template<typename STRING, typename ...ARGS>
330  void exec_no_data(STRING query, ARGS... args)
331  {
332  postgresql::Result res(exec_unchecked(query, args...));
333  res.expect_no_data(query);
334  }
335 
336  template<typename STRING, typename ...ARGS>
337  postgresql::Result exec(STRING query, ARGS... args)
338  {
339  postgresql::Result res(exec_unchecked(query, args...));
340  res.expect_result(query);
341  return res;
342  }
343 
344  template<typename STRING, typename ...ARGS>
345  postgresql::Result exec_one_row(STRING query, ARGS... args)
346  {
347  postgresql::Result res(exec_unchecked(query, args...));
348  res.expect_one_row(query);
349  return res;
350  }
351 
352  postgresql::Result exec_prepared_unchecked(const char* name)
353  {
354  return PQexecPrepared(db, name, 0, nullptr, nullptr, nullptr, 1);
355  }
356 
357  postgresql::Result exec_prepared_unchecked(const std::string& name)
358  {
359  return PQexecPrepared(db, name.c_str(), 0, nullptr, nullptr, nullptr, 1);
360  }
361 
362  template<typename STRING>
363  void exec_prepared_no_data(STRING name)
364  {
365  postgresql::Result res(exec_prepared_unchecked(name));
366  res.expect_no_data(name);
367  }
368 
369  template<typename STRING>
370  postgresql::Result exec_prepared(STRING name)
371  {
372  postgresql::Result res(exec_prepared_unchecked(name));
373  res.expect_result(name);
374  return res;
375  }
376 
377  template<typename STRING>
378  postgresql::Result exec_prepared_one_row(STRING name)
379  {
380  postgresql::Result res(exec_prepared_unchecked(name));
381  res.expect_one_row(name);
382  return res;
383  }
384 
385  template<typename ...ARGS>
386  postgresql::Result exec_prepared_unchecked(const char* name, ARGS... args)
387  {
388  postgresql::Params<ARGS...> params(args...);
389  return PQexecPrepared(db, name, params.count, params.args, params.lengths, params.formats, 1);
390  }
391 
392  template<typename ...ARGS>
393  postgresql::Result exec_prepared_unchecked(const std::string& name, ARGS... args)
394  {
395  postgresql::Params<ARGS...> params(args...);
396  return PQexecPrepared(db, name.c_str(), params.count, params.args, params.lengths, params.formats, 1);
397  }
398 
399  template<typename STRING, typename ...ARGS>
400  void exec_prepared_no_data(STRING name, ARGS... args)
401  {
402  postgresql::Result res(exec_prepared_unchecked(name, args...));
403  res.expect_no_data(name);
404  }
405 
406  template<typename STRING, typename ...ARGS>
407  postgresql::Result exec_prepared(STRING name, ARGS... args)
408  {
409  postgresql::Result res(exec_prepared_unchecked(name, args...));
410  res.expect_result(name);
411  return res;
412  }
413 
414  template<typename STRING, typename ...ARGS>
415  postgresql::Result exec_prepared_one_row(STRING name, ARGS... args)
416  {
417  postgresql::Result res(exec_prepared_unchecked(name, args...));
418  res.expect_one_row(name);
419  return res;
420  }
421 
423  void cancel_running_query_nothrow() noexcept;
424 
426  void discard_all_input_nothrow() noexcept;
427 
429  bool has_table(const std::string& name) override;
430 
436  std::string get_setting(const std::string& key) override;
437 
443  void set_setting(const std::string& key, const std::string& value) override;
444 
446  void drop_settings() override;
447 
451  void drop_table_if_exists(const char* name);
452 
454  int changes();
455 
457  void pqexec(const std::string& query);
464  void pqexec_nothrow(const std::string& query) noexcept;
465 };
466 
467 }
468 }
469 #endif
470 
void _add(unsigned pos, const Datetime &arg, const REST &...rest)
Fill in the argument structures.
Definition: postgresql/internals.h:151
int changes()
Count the number of rows modified by the last query that was run.
Argument list for PQexecParams built at compile time.
Definition: postgresql/internals.h:63
bool get_bool(unsigned row, unsigned col) const
Return a result value, transmitted in binary as a byte (?)
Definition: postgresql/internals.h:208
void open_url(const std::string &connection_string)
Connect to PostgreSQL using a connection URI.
PGconn * db
Database connection.
Definition: postgresql/internals.h:253
Report an PostgreSQL error.
Definition: postgresql/internals.h:36
void pqexec(const std::string &query)
Wrap PQexec.
void expect_result(const std::string &query)
Check that the result successfully returned some (possibly empty) data.
void cancel_running_query_nothrow() noexcept
Send a cancellation command to the server.
uint64_t get_int8(unsigned row, unsigned col) const
Return a result value, transmitted in binary as an 8 bit integer.
void _add(unsigned pos, uint64_t arg, const REST &...rest)
Fill in the argument structures.
Definition: postgresql/internals.h:117
const char * get_string(unsigned row, unsigned col) const
Return a result value, transmitted as a string.
Definition: postgresql/internals.h:232
Wrap a PGresult, taking care of its memory management.
Definition: postgresql/internals.h:163
void _add(unsigned pos, const char *arg, const REST &...rest)
Fill in the argument structures.
Definition: postgresql/internals.h:129
void drop_settings() override
Drop the settings table.
bool has_table(const std::string &name) override
Check if the database contains a table.
std::unique_ptr< Transaction > transaction() override
Begin a transaction.
uint16_t get_int2(unsigned row, unsigned col) const
Return a result value, transmitted in binary as a 2 bit integer.
Definition: postgresql/internals.h:215
Base exception for database errors.
Definition: db/defs.h:54
void expect_one_row(const std::string &query)
Check that the result successfully returned one row of data.
Copyright (C) 2008–2010 ARPA-SIM urpsim@smr.arpa.emr.it
Definition: cmdline.h:17
void expect_success(const std::string &query)
Check that the result was successful.
void pqexec_nothrow(const std::string &query) noexcept
Wrap PQexec but do not throw an exception in case of errors.
Functions used to connect to DB-All.e and insert, query and delete data.
void _add(unsigned pos)
Terminating condition for compile-time arg expansion.
Definition: postgresql/internals.h:88
void _add(unsigned pos, int32_t arg, const REST &...rest)
Fill in the argument structures.
Definition: postgresql/internals.h:105
void _add(unsigned pos, std::nullptr_t arg, const REST &...rest)
Fill in the argument structures.
Definition: postgresql/internals.h:94
void discard_all_input_nothrow() noexcept
Discard all input from an asynchronous request.
unsigned rowcount() const
Get the number of rows in the result.
Definition: postgresql/internals.h:199
Database connection.
Definition: postgresql/internals.h:249
error_postgresql(PGconn *db, const std::string &msg)
Copy informations from the ODBC diagnostic record to the dba error report.
void _add(unsigned pos, const std::string &arg, const REST &...rest)
Fill in the argument structures.
Definition: postgresql/internals.h:140
void set_setting(const std::string &key, const std::string &value) override
Set a value in the settings table.
Datetime get_timestamp(unsigned row, unsigned col) const
Return a result value, transmitted as a timestamp without timezone.
Date and time.
Definition: types.h:147
void prepare(const std::string &name, const std::string &query)
Precompile a query.
Result(Result &&o)
Implement move.
Definition: postgresql/internals.h:172
std::string get_setting(const std::string &key) override
Get a value from the settings table.
void drop_table_if_exists(const char *name)
Delete a table in the database if it exists, otherwise do nothing.
void expect_no_data(const std::string &query)
Check that the result successfully returned no data.
Definition: sql.h:69
uint32_t get_int4(unsigned row, unsigned col) const
Return a result value, transmitted in binary as a 4 bit integer.
Definition: postgresql/internals.h:222
bool is_null(unsigned row, unsigned col) const
Check if a result value is null.
Definition: postgresql/internals.h:202