4#ifndef DBALLE_SQL_POSTGRESQL_H
5#define DBALLE_SQL_POSTGRESQL_H
12#include <unordered_set>
29 const char* what()
const noexcept override {
return msg.c_str(); }
37int64_t encode_datetime(
const Datetime& arg);
38int64_t encode_int64_t(int64_t arg);
41template<
typename... ARGS>
struct Params
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)];
49 Params(
const ARGS&... args)
71 template<
typename... REST>
72 void _add(
unsigned pos, std::nullptr_t arg,
const REST&... rest)
78 _add(pos + 1, rest...);
82 template<
typename... REST>
83 void _add(
unsigned pos, int32_t arg,
const REST&... rest)
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);
90 _add(pos + 1, rest...);
94 template<
typename... REST>
95 void _add(
unsigned pos, uint64_t arg,
const REST&... rest)
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);
102 _add(pos + 1, rest...);
106 template<
typename... REST>
107 void _add(
unsigned pos,
const char* arg,
const REST&... rest)
109 local[pos] =
nullptr;
113 _add(pos + 1, rest...);
117 template<
typename... REST>
118 void _add(
unsigned pos,
const std::string& arg,
const REST&... rest)
120 local[pos] =
nullptr;
121 args[pos] = arg.data();
122 lengths[pos] = arg.size();
124 _add(pos + 1, rest...);
128 template<
typename... REST>
129 void _add(
unsigned pos,
const std::vector<uint8_t>& arg,
const REST&... rest)
131 local[pos] =
nullptr;
132 args[pos] = (
const char*)arg.data();
133 lengths[pos] = arg.size();
135 _add(pos + 1, rest...);
139 template<
typename... REST>
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);
147 _add(pos + 1, rest...);
156 Result() : res(
nullptr) {}
157 Result(PGresult* res) : res(res) {}
164 if (
this == &o)
return *
this;
171 operator bool()
const {
return res !=
nullptr; }
172 operator PGresult*() {
return res; }
173 operator const PGresult*()
const {
return res; }
188 unsigned rowcount()
const {
return PQntuples(res); }
191 bool is_null(
unsigned row,
unsigned col)
const
193 return PQgetisnull(res, row, col);
199 char* val = PQgetvalue(res, row, col);
204 uint16_t
get_int2(
unsigned row,
unsigned col)
const
206 char* val = PQgetvalue(res, row, col);
207 return ntohs(*(uint16_t*)val);
211 uint32_t
get_int4(
unsigned row,
unsigned col)
const
213 char* val = PQgetvalue(res, row, col);
214 return ntohl(*(uint32_t*)val);
218 uint64_t
get_int8(
unsigned row,
unsigned col)
const;
221 std::vector<uint8_t>
get_bytea(
unsigned row,
unsigned col)
const;
226 return PQgetvalue(res, row, col);
245 PGconn*
db =
nullptr;
246 std::unordered_set<std::string> prepared_names;
251 void init_after_connect();
255 void fork_prepare()
override;
256 void fork_parent()
override;
257 void fork_child()
override;
259 void check_connection();
268 static std::shared_ptr<PostgreSQLConnection> create();
270 operator PGconn*() {
return db; }
278 void open_url(
const std::string& connection_string);
281 std::unique_ptr<Transaction>
transaction(
bool readonly=
false)
override;
284 void prepare(
const std::string& name,
const std::string& query);
289 auto res = PQexecParams(
db, query, 0,
nullptr,
nullptr,
nullptr,
nullptr, 1);
298 auto res = PQexecParams(
db, query.c_str(), 0,
nullptr,
nullptr,
nullptr,
nullptr, 1);
304 template<
typename STRING>
305 void exec_no_data(STRING query)
307 postgresql::Result res(exec_unchecked(query));
308 res.expect_no_data(query);
311 template<
typename STRING>
312 postgresql::Result exec(STRING query)
314 postgresql::Result res(exec_unchecked(query));
315 res.expect_result(query);
319 template<
typename STRING>
320 postgresql::Result exec_one_row(STRING query)
322 postgresql::Result res(exec_unchecked(query));
323 res.expect_one_row(query);
327 template<
typename ...ARGS>
328 postgresql::Result exec_unchecked(
const char* query, ARGS... args)
331 postgresql::Params<ARGS...> params(args...);
332 auto res = PQexecParams(
db, query, params.count,
nullptr, params.args, params.lengths, params.formats, 1);
334 throw error_postgresql(
db, std::string(
"cannot execute query ") + 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, params.args, params.lengths, params.formats, 1);
345 throw error_postgresql(
db,
"cannot execute query " + query);
349 template<
typename STRING,
typename ...ARGS>
350 void exec_no_data(STRING query, ARGS... args)
352 postgresql::Result res(exec_unchecked(query, args...));
353 res.expect_no_data(query);
356 template<
typename STRING,
typename ...ARGS>
357 postgresql::Result exec(STRING query, ARGS... args)
359 postgresql::Result res(exec_unchecked(query, args...));
360 res.expect_result(query);
364 template<
typename STRING,
typename ...ARGS>
365 postgresql::Result exec_one_row(STRING query, ARGS... args)
367 postgresql::Result res(exec_unchecked(query, args...));
368 res.expect_one_row(query);
372 postgresql::Result exec_prepared_unchecked(
const char* name)
375 auto res = PQexecPrepared(
db, name, 0,
nullptr,
nullptr,
nullptr, 1);
377 throw error_postgresql(
db, std::string(
"cannot execute prepared query ") + name);
381 postgresql::Result exec_prepared_unchecked(
const std::string& name)
384 auto res = PQexecPrepared(
db, name.c_str(), 0,
nullptr,
nullptr,
nullptr, 1);
386 throw error_postgresql(
db,
"cannot execute prepared query " + name);
390 template<
typename STRING>
391 void exec_prepared_no_data(STRING name)
393 postgresql::Result res(exec_prepared_unchecked(name));
394 res.expect_no_data(name);
397 template<
typename STRING>
398 postgresql::Result exec_prepared(STRING name)
400 postgresql::Result res(exec_prepared_unchecked(name));
401 res.expect_result(name);
405 template<
typename STRING>
406 postgresql::Result exec_prepared_one_row(STRING name)
408 postgresql::Result res(exec_prepared_unchecked(name));
409 res.expect_one_row(name);
413 template<
typename ...ARGS>
414 postgresql::Result exec_prepared_unchecked(
const char* name, ARGS... args)
416 postgresql::Params<ARGS...> params(args...);
417 return PQexecPrepared(
db, name, params.count, params.args, params.lengths, params.formats, 1);
420 template<
typename ...ARGS>
421 postgresql::Result exec_prepared_unchecked(
const std::string& name, ARGS... args)
423 postgresql::Params<ARGS...> params(args...);
424 return PQexecPrepared(
db, name.c_str(), params.count, params.args, params.lengths, params.formats, 1);
427 template<
typename STRING,
typename ...ARGS>
428 void exec_prepared_no_data(STRING name, ARGS... args)
430 postgresql::Result res(exec_prepared_unchecked(name, args...));
431 res.expect_no_data(name);
434 template<
typename STRING,
typename ...ARGS>
435 postgresql::Result exec_prepared(STRING name, ARGS... args)
437 postgresql::Result res(exec_prepared_unchecked(name, args...));
438 res.expect_result(name);
442 template<
typename STRING,
typename ...ARGS>
443 postgresql::Result exec_prepared_one_row(STRING name, ARGS... args)
445 postgresql::Result res(exec_prepared_unchecked(name, args...));
446 res.expect_one_row(name);
458 void set_setting(const std::
string& key, const std::
string& value) override;
460 void execute(const std::
string& query) override;
461 void explain(const std::
string& query, FILE* out) override;
483 void run_single_row_mode(const std::
string& query_desc, std::function<
void(const postgresql::Result&)> dest);
Database connection.
Definition: postgresql.h:242
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:248
PGconn * db
Database connection.
Definition: postgresql.h:245
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:165
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
Argument list for PQexecParams built at compile time.
Definition: postgresql.h:42
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 char *arg, const REST &... rest)
Fill in the argument structures.
Definition: postgresql.h:107
void _add(unsigned pos, int32_t arg, const REST &... rest)
Fill in the argument structures.
Definition: postgresql.h:83
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
void _add(unsigned pos, std::nullptr_t arg, const REST &... rest)
Fill in the argument structures.
Definition: postgresql.h:72
void _add(unsigned pos, uint64_t arg, const REST &... rest)
Fill in the argument structures.
Definition: postgresql.h:95
void _add(unsigned pos, const Datetime &arg, const REST &... rest)
Fill in the argument structures.
Definition: postgresql.h:140
Wrap a PGresult, taking care of its memory management.
Definition: postgresql.h:153
const char * get_string(unsigned row, unsigned col) const
Return a result value, transmitted as a string.
Definition: postgresql.h:224
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
bool get_bool(unsigned row, unsigned col) const
Return a result value, transmitted in binary as a byte (?)
Definition: postgresql.h:197
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:204
Result(Result &&o)
Implement move.
Definition: postgresql.h:161
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:188
bool is_null(unsigned row, unsigned col) const
Check if a result value is null.
Definition: postgresql.h:191