4#ifndef DBALLE_SQL_POSTGRESQL_H
5#define DBALLE_SQL_POSTGRESQL_H
11#include <unordered_set>
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() {}
29 const char* what()
const noexcept override {
return msg.c_str(); }
31 static void throwf(PGconn* db,
const char* fmt, ...)
33 static void throwf(PGresult* db,
const char* fmt, ...)
39int64_t encode_datetime(
const Datetime& arg);
40int64_t encode_int64_t(int64_t arg);
43template <
typename... ARGS>
struct Params
45 static const int count =
sizeof...(ARGS);
46 const char* args[
sizeof...(ARGS)];
47 int lengths[
sizeof...(ARGS)];
48 int formats[
sizeof...(ARGS)];
49 void* local[
sizeof...(ARGS)];
51 Params(
const ARGS&... args) {
_add(0, args...); }
58 Params(
const Params&) =
delete;
59 Params(
const Params&&) =
delete;
60 Params& operator=(
const Params&) =
delete;
61 Params& operator=(
const Params&&) =
delete;
68 template <
typename... REST>
69 void _add(
unsigned pos, std::nullptr_t arg,
const REST&... rest)
75 _add(pos + 1, rest...);
79 template <
typename... REST>
80 void _add(
unsigned pos, int32_t arg,
const REST&... rest)
82 local[pos] = malloc(
sizeof(int32_t));
83 *(int32_t*)local[pos] = (int32_t)htonl((uint32_t)arg);
84 args[pos] = (
const char*)local[pos];
85 lengths[pos] =
sizeof(int32_t);
87 _add(pos + 1, rest...);
91 template <
typename... REST>
92 void _add(
unsigned pos, uint64_t arg,
const REST&... rest)
94 local[pos] = malloc(
sizeof(int64_t));
95 *(int64_t*)local[pos] = encode_int64_t(arg);
96 args[pos] = (
const char*)local[pos];
97 lengths[pos] =
sizeof(int64_t);
99 _add(pos + 1, rest...);
103 template <
typename... REST>
104 void _add(
unsigned pos,
const char* arg,
const REST&... rest)
106 local[pos] =
nullptr;
110 _add(pos + 1, rest...);
114 template <
typename... REST>
115 void _add(
unsigned pos,
const std::string& arg,
const REST&... rest)
117 local[pos] =
nullptr;
118 args[pos] = arg.data();
119 lengths[pos] = arg.size();
121 _add(pos + 1, rest...);
125 template <
typename... REST>
126 void _add(
unsigned pos,
const std::vector<uint8_t>& arg,
129 local[pos] =
nullptr;
130 args[pos] = (
const char*)arg.data();
131 lengths[pos] = arg.size();
133 _add(pos + 1, rest...);
137 template <
typename... REST>
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);
145 _add(pos + 1, rest...);
154 Result() : res(
nullptr) {}
155 Result(PGresult* res) : res(res) {}
156 ~Result() { PQclear(res); }
159 Result(Result&& o) : res(o.res) { o.res =
nullptr; }
170 operator bool()
const {
return res !=
nullptr; }
171 operator PGresult*() {
return res; }
172 operator const PGresult*()
const {
return res; }
187 unsigned rowcount()
const {
return PQntuples(res); }
190 bool is_null(
unsigned row,
unsigned col)
const
192 return PQgetisnull(res, row, col);
198 char* val = PQgetvalue(res, row, col);
203 uint16_t
get_int2(
unsigned row,
unsigned col)
const
205 char* val = PQgetvalue(res, row, col);
206 return ntohs(*(uint16_t*)val);
210 uint32_t
get_int4(
unsigned row,
unsigned col)
const
212 char* val = PQgetvalue(res, row, col);
213 return ntohl(*(uint32_t*)val);
217 uint64_t
get_int8(
unsigned row,
unsigned col)
const;
220 std::vector<uint8_t>
get_bytea(
unsigned row,
unsigned col)
const;
225 return PQgetvalue(res, row, col);
232 Result(
const Result&) =
delete;
233 Result& operator=(
const Result&) =
delete;
239class PostgreSQLConnection :
public Connection
243 PGconn*
db =
nullptr;
244 std::unordered_set<std::string> prepared_names;
249 void init_after_connect();
251 PostgreSQLConnection();
253 void fork_prepare()
override;
254 void fork_parent()
override;
255 void fork_child()
override;
257 void check_connection();
260 PostgreSQLConnection(
const PostgreSQLConnection&) =
delete;
261 PostgreSQLConnection(
const PostgreSQLConnection&&) =
delete;
262 ~PostgreSQLConnection();
264 PostgreSQLConnection& operator=(
const PostgreSQLConnection&) =
delete;
266 static std::shared_ptr<PostgreSQLConnection> create();
268 operator PGconn*() {
return db; }
276 void open_url(
const std::string& connection_string);
279 std::unique_ptr<Transaction>
transaction(
bool readonly =
false)
override;
282 void prepare(
const std::string& name,
const std::string& query);
288 PQexecParams(
db, query, 0,
nullptr,
nullptr,
nullptr,
nullptr, 1);
298 auto res = PQexecParams(db, query.c_str(), 0,
nullptr,
nullptr,
nullptr,
305 template <
typename STRING>
void exec_no_data(STRING query)
307 postgresql::Result res(exec_unchecked(query));
308 res.expect_no_data(query);
311 template <
typename STRING> postgresql::Result exec(STRING query)
313 postgresql::Result res(exec_unchecked(query));
314 res.expect_result(query);
318 template <
typename STRING> postgresql::Result exec_one_row(STRING query)
320 postgresql::Result res(exec_unchecked(query));
321 res.expect_one_row(query);
325 template <
typename... ARGS>
326 postgresql::Result exec_unchecked(
const char* query, ARGS... args)
329 postgresql::Params<ARGS...> params(args...);
330 auto res = PQexecParams(
db, query, params.count,
nullptr, params.args,
331 params.lengths, params.formats, 1);
333 throw error_postgresql(
db, std::string(
"cannot execute query ") +
338 template <
typename... ARGS>
339 postgresql::Result exec_unchecked(
const std::string& query, ARGS... args)
342 postgresql::Params<ARGS...> params(args...);
343 auto res = PQexecParams(
db, query.c_str(), params.count,
nullptr,
344 params.args, params.lengths, params.formats, 1);
346 throw error_postgresql(
db,
"cannot execute query " + query);
350 template <
typename STRING,
typename... ARGS>
351 void exec_no_data(STRING query, ARGS... args)
353 postgresql::Result res(exec_unchecked(query, args...));
354 res.expect_no_data(query);
357 template <
typename STRING,
typename... ARGS>
358 postgresql::Result exec(STRING query, ARGS... args)
360 postgresql::Result res(exec_unchecked(query, args...));
361 res.expect_result(query);
365 template <
typename STRING,
typename... ARGS>
366 postgresql::Result exec_one_row(STRING query, ARGS... args)
368 postgresql::Result res(exec_unchecked(query, args...));
369 res.expect_one_row(query);
373 postgresql::Result exec_prepared_unchecked(
const char* name)
376 auto res = PQexecPrepared(
db, name, 0,
nullptr,
nullptr,
nullptr, 1);
378 throw error_postgresql(
379 db, std::string(
"cannot execute prepared query ") + name);
383 postgresql::Result exec_prepared_unchecked(
const std::string& name)
387 PQexecPrepared(
db, name.c_str(), 0,
nullptr,
nullptr,
nullptr, 1);
389 throw error_postgresql(
db,
"cannot execute prepared query " + name);
393 template <
typename STRING>
void exec_prepared_no_data(STRING name)
395 postgresql::Result res(exec_prepared_unchecked(name));
396 res.expect_no_data(name);
399 template <
typename STRING> postgresql::Result exec_prepared(STRING name)
401 postgresql::Result res(exec_prepared_unchecked(name));
402 res.expect_result(name);
406 template <
typename STRING>
407 postgresql::Result exec_prepared_one_row(STRING name)
409 postgresql::Result res(exec_prepared_unchecked(name));
410 res.expect_one_row(name);
414 template <
typename... ARGS>
415 postgresql::Result exec_prepared_unchecked(
const char* name, ARGS... args)
417 postgresql::Params<ARGS...> params(args...);
418 return PQexecPrepared(
db, name, params.count, params.args,
419 params.lengths, params.formats, 1);
422 template <
typename... ARGS>
423 postgresql::Result exec_prepared_unchecked(
const std::string& name,
426 postgresql::Params<ARGS...> params(args...);
427 return PQexecPrepared(
db, name.c_str(), params.count, params.args,
428 params.lengths, params.formats, 1);
431 template <
typename STRING,
typename... ARGS>
432 void exec_prepared_no_data(STRING name, ARGS... args)
434 postgresql::Result res(exec_prepared_unchecked(name, args...));
435 res.expect_no_data(name);
438 template <
typename STRING,
typename... ARGS>
439 postgresql::Result exec_prepared(STRING name, ARGS... args)
441 postgresql::Result res(exec_prepared_unchecked(name, args...));
442 res.expect_result(name);
446 template <
typename STRING,
typename... ARGS>
447 postgresql::Result exec_prepared_one_row(STRING name, ARGS... args)
449 postgresql::Result res(exec_prepared_unchecked(name, args...));
450 res.expect_one_row(name);
462 void set_setting(const std::
string& key, const std::
string& value) override;
464 void execute(const std::
string& query) override;
465 void explain(const std::
string& query, FILE* out) override;
489 std::function<
void(const postgresql::Result&)> dest);
void drop_table_if_exists(const char *name)
Delete a table in the database if it exists, otherwise do nothing.
void prepare(const std::string &name, const std::string &query)
Precompile a query.
void append_escaped(Querybuf &qb, const char *str)
Escape the string as a literal value and append it to qb.
void run_single_row_mode(const std::string &query_desc, std::function< void(const postgresql::Result &)> dest)
Retrieve query results in single row mode.
void pqexec_nothrow(const std::string &query) noexcept
Wrap PQexec but do not throw an exception in case of errors.
void pqexec(const std::string &query)
Wrap PQexec.
std::unique_ptr< Transaction > transaction(bool readonly=false) override
Begin a transaction.
void set_setting(const std::string &key, const std::string &value) override
Set a value in the settings table.
int changes()
Count the number of rows modified by the last query that was run.
bool forked
Marker to catch attempts to reuse connections in forked processes.
Definition postgresql.h:246
PGconn * db
Database connection.
Definition postgresql.h:243
void open_url(const std::string &connection_string)
Connect to PostgreSQL using a connection URI.
void cancel_running_query_nothrow() noexcept
Send a cancellation command to the server.
void discard_all_input_nothrow() noexcept
Discard all input from an asynchronous request.
void explain(const std::string &query, FILE *out) override
Format and print the EXPLAIN output for the query to the given file.
void drop_settings() override
Drop the settings table.
bool has_table(const std::string &name) override
Check if the database contains a table.
void execute(const std::string &query) override
Execute a query without reading its results.
std::string get_setting(const std::string &key) override
Get a value from the settings table.
#define WREPORT_THROWF_ATTRS(a, b)
Common infrastructure for talking with SQL databases.
Date and time.
Definition types.h:164
Error in case of failed database operations.
Definition error.h:22
String buffer for composing database queries.
Definition querybuf.h:16
Report an PostgreSQL error.
Definition postgresql.h:21
void _add(unsigned pos, const std::string &arg, const REST &... rest)
Fill in the argument structures.
Definition postgresql.h:115
void _add(unsigned pos, const char *arg, const REST &... rest)
Fill in the argument structures.
Definition postgresql.h:104
void _add(unsigned pos, int32_t arg, const REST &... rest)
Fill in the argument structures.
Definition postgresql.h:80
void _add(unsigned pos)
Terminating condition for compile-time arg expansion.
Definition postgresql.h:65
void _add(unsigned pos, const std::vector< uint8_t > &arg, const REST &... rest)
Fill in the argument structures.
Definition postgresql.h:126
void _add(unsigned pos, std::nullptr_t arg, const REST &... rest)
Fill in the argument structures.
Definition postgresql.h:69
void _add(unsigned pos, uint64_t arg, const REST &... rest)
Fill in the argument structures.
Definition postgresql.h:92
void _add(unsigned pos, const Datetime &arg, const REST &... rest)
Fill in the argument structures.
Definition postgresql.h:138
Wrap a PGresult, taking care of its memory management.
Definition postgresql.h:151
const char * get_string(unsigned row, unsigned col) const
Return a result value, transmitted as a string.
Definition postgresql.h:223
uint32_t get_int4(unsigned row, unsigned col) const
Return a result value, transmitted in binary as a 4 bit integer.
Definition postgresql.h:210
bool get_bool(unsigned row, unsigned col) const
Return a result value, transmitted in binary as a byte (?)
Definition postgresql.h:196
uint64_t get_int8(unsigned row, unsigned col) const
Return a result value, transmitted in binary as an 8 bit integer.
void expect_success(const std::string &query)
Check that the result was successful.
uint16_t get_int2(unsigned row, unsigned col) const
Return a result value, transmitted in binary as a 2 bit integer.
Definition postgresql.h:203
Result(Result &&o)
Implement move.
Definition postgresql.h:159
void expect_no_data(const std::string &query)
Check that the result successfully returned no data.
std::vector< uint8_t > get_bytea(unsigned row, unsigned col) const
Return a result value, transmitted in binary as an 8 bit integer.
void expect_result(const std::string &query)
Check that the result successfully returned some (possibly empty) data.
void expect_one_row(const std::string &query)
Check that the result successfully returned one row of data.
Datetime get_timestamp(unsigned row, unsigned col) const
Return a result value, transmitted as a timestamp without timezone.
unsigned rowcount() const
Get the number of rows in the result.
Definition postgresql.h:187
bool is_null(unsigned row, unsigned col) const
Check if a result value is null.
Definition postgresql.h:190